/*
  Copyright 2019 Equinor.
  Copyright 2016 Statoil ASA.

  This file is part of the Open Porous Media project (OPM).

  OPM is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  OPM is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with OPM.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "config.h"

#define BOOST_TEST_MODULE Tabular_INIT_Output
#include <boost/test/unit_test.hpp>

#include <opm/output/eclipse/Tables.hpp>
#include <opm/output/eclipse/VectorItems/tabdims.hpp>

#include <opm/input/eclipse/EclipseState/EclipseState.hpp>

#include <opm/input/eclipse/Units/UnitSystem.hpp>

#include <opm/input/eclipse/Deck/Deck.hpp>
#include <opm/input/eclipse/Parser/Parser.hpp>

#include <cstddef>
#include <exception>
#include <initializer_list>
#include <stdexcept>
#include <string>
#include <vector>

using Ix = ::Opm::RestartIO::Helpers::VectorItems::TabDims::index;

namespace {
    template <class Collection1, class Collection2>
    void check_is_close(const Collection1& c1, const Collection2& c2)
    {
        BOOST_REQUIRE_EQUAL(c1.size(), c2.size());

        if (! c1.empty()) {
            auto i1 = c1.begin(), e1 = c1.end();
            auto i2 = c2.begin();

            for (; i1 != e1; ++i1, ++i2) {
                BOOST_CHECK_CLOSE(*i1, *i2, 1.0e-10);
            }
        }
    }

    std::vector<double>
    makeTable(const std::size_t             ncol,
              std::initializer_list<double> data)
    {
        auto result = std::vector<double>(data.size(), 0.0);
        const auto nrows = data.size() / ncol;

        auto di = std::begin(data);
        for (auto i = 0*nrows; i < nrows; ++i) {
            for (auto j = 0*ncol; j < ncol; ++j, ++di) {
                result[i + j*nrows] = *di;
            }
        }

        return result;
    }

    namespace SPE1 {            // Family II (SGFN, SOF{2,3}, SWFN)
        namespace TwoPhase {
            namespace GasOil {
                Opm::EclipseState satfuncTables()
                {
                    const auto* input = R"(
RUNSPEC
OIL
GAS

METRIC

DIMENS
  1 1 1 /

TABDIMS
/

-- =======================================
GRID

DXV
  1 /

DYV
  1 /

DZV
  0.1 /

DEPTHZ
  4*2000.0 /

PERMX
  100.0 /

COPY
  'PERMX' 'PERMY' /
  'PERMX' 'PERMZ' /
/

MULTIPLY
  'PERMZ' 0.1 /
/

PORO
  0.3 /

-- =======================================
PROPS

SGFN
-- SPE 1 Table
 0       0       0
 0.001   0       0
 0.02    0       0
 0.05    0.005   0
 0.12    0.025   0
 0.2     0.075   0
 0.25    0.125   0
 0.3     0.190   0
 0.4     0.410   0
 0.45    0.60    0
 0.5     0.72    0
 0.6     0.87    0
 0.7     0.94    0
 0.85    0.98    0
 0.88    0.984   0 /

SOF2
--  SPE 1 Table
    0        0
    0.03     0
    0.18     0
    0.28     0.0001
    0.38     0.001
    0.43     0.01
    0.48     0.021
    0.58     0.09
    0.63     0.2
    0.68     0.35
    0.76     0.7
    0.83     0.98
    0.86     0.997
    0.879    1
    0.88     1    /

DENSITY
  853.0  1014.0  0.75 /

END
)";

                    const auto deck = Opm::Deck{
                        Opm::Parser{}.parseString(input)
                    };

                    return Opm::EclipseState{deck};
                }

                std::vector<double> expect_SGFN()
                {
                    return makeTable(5, {
                               0,                        0,          0,    1.000000000000000e+20,    1.0e+20,
                        1.00e-03,                        0,          0,                        0,          0,
                        2.00e-02,                        0,          0,                        0,          0,
                        5.00e-02,    5.000000000000000e-03,          0,    1.666666666666667e-01,          0,
                        1.20e-01,    2.500000000000000e-02,          0,    2.857142857142858e-01,          0,
                        2.00e-01,    7.500000000000000e-02,          0,    6.249999999999998e-01,          0,
                        2.50e-01,    1.250000000000000e-01,          0,    1.000000000000000e+00,          0,
                        3.00e-01,    1.900000000000000e-01,          0,    1.300000000000000e+00,          0,
                        4.00e-01,    4.100000000000000e-01,          0,    2.199999999999999e+00,          0,
                        4.50e-01,    6.000000000000000e-01,          0,    3.800000000000001e+00,          0,
                        5.00e-01,    7.200000000000000e-01,          0,    2.400000000000000e+00,          0,
                        6.00e-01,    8.700000000000000e-01,          0,    1.500000000000001e+00,          0,
                        7.00e-01,    9.399999999999999e-01,          0,    6.999999999999996e-01,          0,
                        8.50e-01,    9.800000000000000e-01,          0,    2.666666666666669e-01,          0,
                        8.80e-01,    9.840000000000000e-01,          0,    1.333333333333333e-01,          0,
                        1.00e+20,    1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,    1.0e+20,
                        1.00e+20,    1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,    1.0e+20,
                        1.00e+20,    1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,    1.0e+20,
                        1.00e+20,    1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,    1.0e+20,
                        1.00e+20,    1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,    1.0e+20,
                    });
                }

                std::vector<double> expect_SOFN()
                {
                    return makeTable(3, {
                               0,           0,    1.000000000000000e+20,
                        3.00e-02,           0,                        0,
                        1.80e-01,           0,                        0,
                        2.80e-01,    1.00e-04,    9.999999999999998e-04,
                        3.80e-01,    1.00e-03,    9.000000000000001e-03,
                        4.30e-01,    1.00e-02,    1.800000000000000e-01,
                        4.80e-01,    2.10e-02,    2.200000000000001e-01,
                        5.80e-01,    9.00e-02,    6.900000000000001e-01,
                        6.30e-01,    2.00e-01,    2.199999999999998e+00,
                        6.80e-01,    3.50e-01,    2.999999999999997e+00,
                        7.60e-01,    7.00e-01,    4.375000000000002e+00,
                        8.30e-01,    9.80e-01,    4.000000000000004e+00,
                        8.60e-01,    9.97e-01,    5.666666666666667e-01,
                        8.79e-01,    1.00e+00,    1.578947368421053e-01,
                        8.80e-01,    1.00e+00,                        0,
                        1.00e+20,    1.00e+20,    1.000000000000000e+20,
                        1.00e+20,    1.00e+20,    1.000000000000000e+20,
                        1.00e+20,    1.00e+20,    1.000000000000000e+20,
                        1.00e+20,    1.00e+20,    1.000000000000000e+20,
                        1.00e+20,    1.00e+20,    1.000000000000000e+20,
                    });
                }
            } // GasOil

            namespace OilWater {
                Opm::EclipseState satfuncTables()
                {
                    const auto* input = R"(
RUNSPEC
WATER
OIL

METRIC

DIMENS
  1 1 1 /

TABDIMS
/

-- =======================================
GRID

DXV
  1 /

DYV
  1 /

DZV
  0.1 /

DEPTHZ
  4*2000.0 /

PERMX
  100.0 /

COPY
  'PERMX' 'PERMY' /
  'PERMX' 'PERMZ' /
/

MULTIPLY
  'PERMZ' 0.1 /
/

PORO
  0.3 /

-- =======================================
PROPS

SWFN
-- SPE 1 Table
 0.12    0                       0
 0.18    4.64876033057851E-008   0
 0.24    0.000000186             0
 0.3     4.18388429752066E-007   0
 0.36    7.43801652892562E-007   0
 0.42    1.16219008264463E-006   0
 0.48    1.67355371900826E-006   0
 0.54    2.27789256198347E-006   0
 0.6     2.97520661157025E-006   0
 0.66    3.7654958677686E-006    0
 0.72    4.64876033057851E-006   0
 0.78    0.000005625             0
 0.84    6.69421487603306E-006   0
 0.91    8.05914256198347E-006   0
 1       0.00001                 0 /

SOF2
--  SPE 1 Table
    0        0
    0.03     0
    0.18     0
    0.28     0.0001
    0.38     0.001
    0.43     0.01
    0.48     0.021
    0.58     0.09
    0.63     0.2
    0.68     0.35
    0.76     0.7
    0.83     0.98
    0.86     0.997
    0.879    1
    0.88     1
    /

DENSITY
  853.0  1014.0  0.75 /

END
)";

                    const auto deck = Opm::Deck{
                        Opm::Parser{}.parseString(input)
                    };

                    return Opm::EclipseState{deck};
                }

                std::vector<double> expect_SOFN()
                {
                    return makeTable(3, {
                               0,           0,    1.000000000000000e+20,
                        3.00e-02,           0,                        0,
                        1.80e-01,           0,                        0,
                        2.80e-01,    1.00e-04,    9.999999999999998e-04,
                        3.80e-01,    1.00e-03,    9.000000000000001e-03,
                        4.30e-01,    1.00e-02,    1.800000000000000e-01,
                        4.80e-01,    2.10e-02,    2.200000000000001e-01,
                        5.80e-01,    9.00e-02,    6.900000000000001e-01,
                        6.30e-01,    2.00e-01,    2.199999999999998e+00,
                        6.80e-01,    3.50e-01,    2.999999999999997e+00,
                        7.60e-01,    7.00e-01,    4.375000000000002e+00,
                        8.30e-01,    9.80e-01,    4.000000000000004e+00,
                        8.60e-01,    9.97e-01,    5.666666666666667e-01,
                        8.79e-01,    1.00e+00,    1.578947368421053e-01,
                        8.80e-01,    1.00e+00,                        0,
                        1.00e+20,    1.00e+20,    1.000000000000000e+20,
                        1.00e+20,    1.00e+20,    1.000000000000000e+20,
                        1.00e+20,    1.00e+20,    1.000000000000000e+20,
                        1.00e+20,    1.00e+20,    1.000000000000000e+20,
                        1.00e+20,    1.00e+20,    1.000000000000000e+20,
                    });
                }

                std::vector<double> expect_SWFN()
                {
                    return makeTable(5, {
                        1.20e-01,                        0,          0,    1.000000000000000e+20,    1.0e+20,
                        1.80e-01,                        0,          0,                        0,          0,
                        2.40e-01,                        0,          0,                        0,          0,
                        3.00e-01,                        0,          0,                        0,          0,
                        3.60e-01,                        0,          0,                        0,          0,
                        4.20e-01,    1.162190082644630e-06,          0,    1.936983471074384e-05,          0,
                        4.80e-01,    1.673553719008260e-06,          0,    8.522727272727165e-06,          0,
                        5.40e-01,    2.277892561983470e-06,          0,    1.007231404958682e-05,          0,
                        6.00e-01,    2.975206611570250e-06,          0,    1.162190082644635e-05,          0,
                        6.60e-01,    3.765495867768600e-06,          0,    1.317148760330582e-05,          0,
                        7.20e-01,    4.648760330578510e-06,          0,    1.472107438016518e-05,          0,
                        7.80e-01,    5.625000000000000e-06,          0,    1.627066115702482e-05,          0,
                        8.40e-01,    6.694214876033060e-06,          0,    1.782024793388435e-05,          0,
                        9.10e-01,    8.059142561983471e-06,          0,    1.949896694214870e-05,          0,
                        1.00e+00,    1.000000000000000e-05,          0,    2.156508264462812e-05,          0,
                        1.00e+20,    1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,    1.0e+20,
                        1.00e+20,    1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,    1.0e+20,
                        1.00e+20,    1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,    1.0e+20,
                        1.00e+20,    1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,    1.0e+20,
                        1.00e+20,    1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,    1.0e+20,
                    });
                }
            } // OilWater
        } // TwoPhase

        namespace ThreePhase {
            Opm::EclipseState satfuncTables()
            {
                const auto* input = R"(
RUNSPEC
WATER
OIL
GAS

METRIC

DIMENS
  1 1 1 /

TABDIMS
/

-- =======================================
GRID

DXV
  1 /

DYV
  1 /

DZV
  0.1 /

DEPTHZ
  4*2000.0 /

PERMX
  100.0 /

COPY
  'PERMX' 'PERMY' /
  'PERMX' 'PERMZ' /
/

MULTIPLY
  'PERMZ' 0.1 /
/

PORO
  0.3 /

-- =======================================
PROPS

SWFN
-- SPE 1 Table
 0.12    0                       0
 0.18    4.64876033057851E-008   0
 0.24    0.000000186             0
 0.3     4.18388429752066E-007   0
 0.36    7.43801652892562E-007   0
 0.42    1.16219008264463E-006   0
 0.48    1.67355371900826E-006   0
 0.54    2.27789256198347E-006   0
 0.6     2.97520661157025E-006   0
 0.66    3.7654958677686E-006    0
 0.72    4.64876033057851E-006   0
 0.78    0.000005625             0
 0.84    6.69421487603306E-006   0
 0.91    8.05914256198347E-006   0
 1       0.00001                 0 /

SGFN
-- SPE 1 Table
 0       0       0
 0.001   0       0
 0.02    0       0
 0.05    0.005   0
 0.12    0.025   0
 0.2     0.075   0
 0.25    0.125   0
 0.3     0.190   0
 0.4     0.410   0
 0.45    0.60    0
 0.5     0.72    0
 0.6     0.87    0
 0.7     0.94    0
 0.85    0.98    0
 0.88    0.984   0 /

SOF3
--  SPE 1 Table
    0        0        0
    0.03     0        0
    0.18     0        0
    0.28     0.0001   0.0001
    0.38     0.001    0.001
    0.43     0.01     0.01
    0.48     0.021    0.021
    0.58     0.09     0.09
    0.63     0.2      0.2
    0.68     0.35     0.35
    0.76     0.7      0.7
    0.83     0.98     0.98
    0.86     0.997    0.997
    0.879    1        1
    0.88     1        1    /

DENSITY
  853.0  1014.0  0.75 /

END
)";

                const auto deck = Opm::Deck{
                    Opm::Parser{}.parseString(input)
                };

                return Opm::EclipseState{deck};
            }

            std::vector<double> expect_SGFN()
            {
                return makeTable(5, {
                           0,                        0,          0,    1.000000000000000e+20,    1.0e+20,
                    1.00e-03,                        0,          0,                        0,          0,
                    2.00e-02,                        0,          0,                        0,          0,
                    5.00e-02,    5.000000000000000e-03,          0,    1.666666666666667e-01,          0,
                    1.20e-01,    2.500000000000000e-02,          0,    2.857142857142858e-01,          0,
                    2.00e-01,    7.500000000000000e-02,          0,    6.249999999999998e-01,          0,
                    2.50e-01,    1.250000000000000e-01,          0,    1.000000000000000e+00,          0,
                    3.00e-01,    1.900000000000000e-01,          0,    1.300000000000000e+00,          0,
                    4.00e-01,    4.100000000000000e-01,          0,    2.199999999999999e+00,          0,
                    4.50e-01,    6.000000000000000e-01,          0,    3.800000000000001e+00,          0,
                    5.00e-01,    7.200000000000000e-01,          0,    2.400000000000000e+00,          0,
                    6.00e-01,    8.700000000000000e-01,          0,    1.500000000000001e+00,          0,
                    7.00e-01,    9.399999999999999e-01,          0,    6.999999999999996e-01,          0,
                    8.50e-01,    9.800000000000000e-01,          0,    2.666666666666669e-01,          0,
                    8.80e-01,    9.840000000000000e-01,          0,    1.333333333333333e-01,          0,
                    1.00e+20,    1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,    1.0e+20,
                    1.00e+20,    1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,    1.0e+20,
                    1.00e+20,    1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,    1.0e+20,
                    1.00e+20,    1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,    1.0e+20,
                    1.00e+20,    1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,    1.0e+20,
                });
            }

            std::vector<double> expect_SOFN()
            {
                return makeTable(5, {
                           0,           0,           0,    1.000000000000000e+20,    1.000000000000000e+20,
                    3.00e-02,           0,           0,                        0,                        0,
                    1.80e-01,           0,           0,                        0,                        0,
                    2.80e-01,    1.00e-04,    1.00e-04,    9.999999999999998e-04,    9.999999999999998e-04,
                    3.80e-01,    1.00e-03,    1.00e-03,    9.000000000000001e-03,    9.000000000000001e-03,
                    4.30e-01,    1.00e-02,    1.00e-02,    1.800000000000000e-01,    1.800000000000000e-01,
                    4.80e-01,    2.10e-02,    2.10e-02,    2.200000000000001e-01,    2.200000000000001e-01,
                    5.80e-01,    9.00e-02,    9.00e-02,    6.900000000000001e-01,    6.900000000000001e-01,
                    6.30e-01,    2.00e-01,    2.00e-01,    2.199999999999998e+00,    2.199999999999998e+00,
                    6.80e-01,    3.50e-01,    3.50e-01,    2.999999999999997e+00,    2.999999999999997e+00,
                    7.60e-01,    7.00e-01,    7.00e-01,    4.375000000000002e+00,    4.375000000000002e+00,
                    8.30e-01,    9.80e-01,    9.80e-01,    4.000000000000004e+00,    4.000000000000004e+00,
                    8.60e-01,    9.97e-01,    9.97e-01,    5.666666666666667e-01,    5.666666666666667e-01,
                    8.79e-01,    1.00e+00,    1.00e+00,    1.578947368421053e-01,    1.578947368421053e-01,
                    8.80e-01,    1.00e+00,    1.00e+00,                        0,                        0,
                    1.00e+20,    1.00e+20,    1.00e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.00e+20,    1.00e+20,    1.00e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.00e+20,    1.00e+20,    1.00e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.00e+20,    1.00e+20,    1.00e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.00e+20,    1.00e+20,    1.00e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                });
            }

            std::vector<double> expect_SWFN()
            {
                return makeTable(5, {
                    1.20e-01,                        0,          0,    1.000000000000000e+20,    1.0e+20,
                    1.80e-01,                        0,          0,                        0,          0,
                    2.40e-01,                        0,          0,                        0,          0,
                    3.00e-01,                        0,          0,                        0,          0,
                    3.60e-01,                        0,          0,                        0,          0,
                    4.20e-01,    1.162190082644630e-06,          0,    1.936983471074384e-05,          0,
                    4.80e-01,    1.673553719008260e-06,          0,    8.522727272727165e-06,          0,
                    5.40e-01,    2.277892561983470e-06,          0,    1.007231404958682e-05,          0,
                    6.00e-01,    2.975206611570250e-06,          0,    1.162190082644635e-05,          0,
                    6.60e-01,    3.765495867768600e-06,          0,    1.317148760330582e-05,          0,
                    7.20e-01,    4.648760330578510e-06,          0,    1.472107438016518e-05,          0,
                    7.80e-01,    5.625000000000000e-06,          0,    1.627066115702482e-05,          0,
                    8.40e-01,    6.694214876033060e-06,          0,    1.782024793388435e-05,          0,
                    9.10e-01,    8.059142561983471e-06,          0,    1.949896694214870e-05,          0,
                    1.00e+00,    1.000000000000000e-05,          0,    2.156508264462812e-05,          0,
                    1.00e+20,    1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,    1.0e+20,
                    1.00e+20,    1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,    1.0e+20,
                    1.00e+20,    1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,    1.0e+20,
                    1.00e+20,    1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,    1.0e+20,
                    1.00e+20,    1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,    1.0e+20,
                });
            }

            Opm::EclipseState satfuncTablesTabDimsMismatch()
            {
                const auto* input = R"(
RUNSPEC
WATER
OIL
GAS

METRIC

DIMENS
  1 1 1 /

TABDIMS
-- TABDIMS(3) == 3 => size output according to maximum #rows (= 15)
  2* 3
/

-- =======================================
GRID

DXV
  1 /

DYV
  1 /

DZV
  0.1 /

DEPTHZ
  4*2000.0 /

PERMX
  100.0 /

COPY
  'PERMX' 'PERMY' /
  'PERMX' 'PERMZ' /
/

MULTIPLY
  'PERMZ' 0.1 /
/

PORO
  0.3 /

-- =======================================
PROPS

SWOF
-- SPE 1 Table
0.12	0    		 	1	0
0.18	4.64876033057851E-008	1	0
0.24	0.000000186		0.997	0
0.3	4.18388429752066E-007	0.98	0
0.36	7.43801652892562E-007	0.7	0
0.42	1.16219008264463E-006	0.35	0
0.48	1.67355371900826E-006	0.2	0
0.54	2.27789256198347E-006	0.09	0
0.6	2.97520661157025E-006	0.021	0
0.66	3.7654958677686E-006	0.01	0
0.72	4.64876033057851E-006	0.001	0
0.78	0.000005625		0.0001	0
0.84	6.69421487603306E-006	0	0
0.91	8.05914256198347E-006	0	0
1	0.00001			0	0 /

SGOF
-- SPE 1 Table
0	0	1	0
0.001	0	1	0
0.02	0	0.997	0
0.05	0.005	0.980	0
0.12	0.025	0.700	0
0.2	0.075	0.350	0
0.25	0.125	0.200	0
0.3	0.190	0.090	0
0.4	0.410	0.021	0
0.45	0.60	0.010	0
0.5	0.72	0.001	0
0.6	0.87	0.0001	0
0.7	0.94	0.000	0
0.85	0.98	0.000	0
0.88	0.984	0.000	0 /

DENSITY
  853.0  1014.0  0.75 /

END
)";

                const auto deck = Opm::Deck{
                    Opm::Parser{}.parseString(input)
                };

                return Opm::EclipseState{deck};
            }

            std::vector<double> expect_SGFN_TabDimsMismatch()
            {
                return makeTable(5, {
                           0,                        0,          0,    1.000000000000000e+20,    1.0e+20,
                    1.00e-03,                        0,          0,                        0,          0,
                    2.00e-02,                        0,          0,                        0,          0,
                    5.00e-02,    5.000000000000000e-03,          0,    1.666666666666667e-01,          0,
                    1.20e-01,    2.500000000000000e-02,          0,    2.857142857142858e-01,          0,
                    2.00e-01,    7.500000000000000e-02,          0,    6.249999999999998e-01,          0,
                    2.50e-01,    1.250000000000000e-01,          0,    1.000000000000000e+00,          0,
                    3.00e-01,    1.900000000000000e-01,          0,    1.300000000000000e+00,          0,
                    4.00e-01,    4.100000000000000e-01,          0,    2.199999999999999e+00,          0,
                    4.50e-01,    6.000000000000000e-01,          0,    3.800000000000001e+00,          0,
                    5.00e-01,    7.200000000000000e-01,          0,    2.400000000000000e+00,          0,
                    6.00e-01,    8.700000000000000e-01,          0,    1.500000000000001e+00,          0,
                    7.00e-01,    9.399999999999999e-01,          0,    6.999999999999996e-01,          0,
                    8.50e-01,    9.800000000000000e-01,          0,    2.666666666666669e-01,          0,
                    8.80e-01,    9.840000000000000e-01,          0,    1.333333333333333e-01,          0,
                });
            }

            std::vector<double> expect_SOFN_TabDimsMismatch()
            {
                return makeTable(5, {
                    0.000000000000000e+00, 0.000000000000000e+00, 0.000000000000000e+00, 1.000000000000000e+20, 1.000000000000000e+20,
                    3.000000000000003e-02, 0.000000000000000e+00, 0.000000000000000e+00, 0.000000000000000e+00, 0.000000000000000e+00,
                    8.999999999999997e-02, 0.000000000000000e+00, 0.000000000000000e+00, 0.000000000000000e+00, 0.000000000000000e+00,
                    1.600000000000000e-01, 0.000000000000000e+00, 0.000000000000000e+00, 0.000000000000000e+00, 0.000000000000000e+00,
                    1.800000000000000e-01, 3.333333333333340e-05, 0.000000000000000e+00, 1.666666666666669e-03, 0.000000000000000e+00,
                    2.200000000000000e-01, 1.000000000000000e-04, 3.999999999999994e-05, 1.666666666666668e-03, 1.000000000000000e-03,
                    2.800000000000000e-01, 1.000000000000000e-03, 1.000000000000000e-04, 1.499999999999999e-02, 1.000000000000000e-03,
                    3.400000000000000e-01, 1.000000000000000e-02, 6.399999999999997e-04, 1.500000000000002e-01, 9.000000000000003e-03,
                    3.800000000000000e-01, 1.733333333333333e-02, 1.000000000000000e-03, 1.833333333333332e-01, 8.999999999999999e-03,
                    4.000000000000000e-01, 2.100000000000000e-02, 4.600000000000004e-03, 1.833333333333333e-01, 1.800000000000000e-01,
                    4.300000000000000e-01, 5.550000000000000e-02, 1.000000000000000e-02, 1.150000000000001e+00, 1.800000000000000e-01,
                    4.600000000000000e-01, 9.000000000000000e-02, 1.660000000000000e-02, 1.150000000000001e+00, 2.200000000000001e-01,
                    4.800000000000000e-01, 1.266666666666666e-01, 2.100000000000000e-02, 1.833333333333331e+00, 2.200000000000000e-01,
                    5.200000000000000e-01, 2.000000000000000e-01, 4.860000000000000e-02, 1.833333333333332e+00, 6.899999999999995e-01,
                    5.800000000000001e-01, 3.500000000000000e-01, 9.000000000000000e-02, 2.499999999999997e+00, 6.899999999999993e-01,
                    6.300000000000000e-01, 6.416666666666665e-01, 2.000000000000000e-01, 5.833333333333338e+00, 2.200000000000003e+00,
                    6.400000000000000e-01, 7.000000000000000e-01, 2.300000000000001e-01, 5.833333333333341e+00, 3.000000000000003e+00,
                    6.799999999999999e-01, 8.866666666666665e-01, 3.500000000000000e-01, 4.666666666666672e+00, 3.000000000000004e+00,
                    7.000000000000000e-01, 9.800000000000000e-01, 4.375000000000000e-01, 4.666666666666671e+00, 4.374999999999997e+00,
                    7.600000000000000e-01, 9.970000000000000e-01, 7.000000000000000e-01, 2.833333333333333e-01, 4.374999999999996e+00,
                    8.200000000000001e-01, 1.000000000000000e+00, 9.400000000000004e-01, 5.000000000000000e-02, 4.000000000000004e+00,
                    8.300000000000000e-01, 1.000000000000000e+00, 9.800000000000000e-01, 0.000000000000000e+00, 4.000000000000000e+00,
                    8.600000000000000e-01, 1.000000000000000e+00, 9.970000000000000e-01, 0.000000000000000e+00, 5.666666666666667e-01,
                    8.790000000000000e-01, 1.000000000000000e+00, 1.000000000000000e+00, 0.000000000000000e+00, 1.578947368421053e-01,
                    8.800000000000000e-01, 1.000000000000000e+00, 1.000000000000000e+00, 0.000000000000000e+00, 0.000000000000000e+00,
                    1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20,
                    1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20,
                    1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20,
                    1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20,
                    1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20, 1.000000000000000e+20,
                });
            }

            std::vector<double> expect_SWFN_TabDimsMismatch()
            {
                return makeTable(5, {
                    1.20e-01,                        0,          0,    1.000000000000000e+20,    1.0e+20,
                    1.80e-01,                        0,          0,                        0,          0,
                    2.40e-01,                        0,          0,                        0,          0,
                    3.00e-01,                        0,          0,                        0,          0,
                    3.60e-01,                        0,          0,                        0,          0,
                    4.20e-01,    1.162190082644630e-06,          0,    1.936983471074384e-05,          0,
                    4.80e-01,    1.673553719008260e-06,          0,    8.522727272727165e-06,          0,
                    5.40e-01,    2.277892561983470e-06,          0,    1.007231404958682e-05,          0,
                    6.00e-01,    2.975206611570250e-06,          0,    1.162190082644635e-05,          0,
                    6.60e-01,    3.765495867768600e-06,          0,    1.317148760330582e-05,          0,
                    7.20e-01,    4.648760330578510e-06,          0,    1.472107438016518e-05,          0,
                    7.80e-01,    5.625000000000000e-06,          0,    1.627066115702482e-05,          0,
                    8.40e-01,    6.694214876033060e-06,          0,    1.782024793388435e-05,          0,
                    9.10e-01,    8.059142561983471e-06,          0,    1.949896694214870e-05,          0,
                    1.00e+00,    1.000000000000000e-05,          0,    2.156508264462812e-05,          0,
                });
            }
        } // ThreePhase
    } // SPE1

    namespace SPE9 {            // Family One (SGOF and SWOF)
        namespace TwoPhase {
            namespace GasOil {
                Opm::EclipseState satfuncTables()
                {
                    const auto* input = R"(
RUNSPEC
OIL
GAS

METRIC

DIMENS
  1 1 1 /

TABDIMS
    1    1   30   20    1   20 /

-- =======================================
GRID

DXV
  1 /

DYV
  1 /

DZV
  0.1 /

DEPTHZ
  4*2000.0 /

PERMX
  100.0 /

COPY
  'PERMX' 'PERMY' /
  'PERMX' 'PERMZ' /
/

MULTIPLY
  'PERMZ' 0.1 /
/

PORO
  0.3 /

-- =======================================
PROPS

SGOF
-- SPE 9 Table
                         0                         0     1.000000000000000e+00                         0
     4.000000000000000e-02                         0     6.000000000000000e-01     1.378951458633672e-02
     1.000000000000000e-01     2.200000000000000e-02     3.300000000000000e-01     3.447378646584180e-02
     2.000000000000000e-01     1.000000000000000e-01     1.000000000000000e-01     6.894757293168360e-02
     3.000000000000000e-01     2.400000000000000e-01     2.000000000000000e-02     1.034213593975254e-01
     4.000000000000000e-01     3.400000000000000e-01                         0     1.378951458633672e-01
     5.000000000000000e-01     4.200000000000000e-01                         0     1.723689323292090e-01
     6.000000000000000e-01     5.000000000000000e-01                         0     2.068427187950508e-01
     7.000000000000000e-01     8.125000000000000e-01                         0     2.413165052608926e-01
     8.489100000000001e-01     9.635000000000000e-01                         0     2.633797285990314e-01 /

DENSITY
  853.0  1014.0  0.75 /

END
)";

                    const auto deck = Opm::Deck{
                        Opm::Parser{}.parseString(input)
                    };

                    return Opm::EclipseState{deck};
                }

                std::vector<double> expect_SGFN()
                {
                    // Columns 1, 2, 4 (+ derivatives) of SGOF
                    return makeTable(5, {
                                 0,            0,                        0,    1.000000000000000e+20,    1.000000000000000e+20,
                        4.0000e-02,            0,    1.378951458633672e-02,                        0,    3.447378646584180e-01,
                        1.0000e-01,    2.200e-02,    3.447378646584180e-02,    3.666666666666666e-01,    3.447378646584180e-01,
                        2.0000e-01,    1.000e-01,    6.894757293168360e-02,    7.800000000000001e-01,    3.447378646584180e-01,
                        3.0000e-01,    2.400e-01,    1.034213593975254e-01,    1.400000000000000e+00,    3.447378646584180e-01,
                        4.0000e-01,    3.400e-01,    1.378951458633672e-01,    1.000000000000000e+00,    3.447378646584179e-01,
                        5.0000e-01,    4.200e-01,    1.723689323292090e-01,    7.999999999999998e-01,    3.447378646584180e-01,
                        6.0000e-01,    5.000e-01,    2.068427187950508e-01,    8.000000000000004e-01,    3.447378646584180e-01,
                        7.0000e-01,    8.125e-01,    2.413165052608926e-01,    3.125000000000001e+00,    3.447378646584180e-01,
                        8.4891e-01,    9.635e-01,    2.633797285990314e-01,    1.014035323349674e+00,    1.481648199458648e-01,
                        1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                        1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                        1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                        1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                        1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                        1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                        1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                        1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                        1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                        1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                        1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                        1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                        1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                        1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                        1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                        1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                        1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                        1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                        1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                        1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    });
                }

                std::vector<double> expect_SOFN()
                {
                    // Columns 1 and 3 from SGOF (using So = 1 - Sg in 2p
                    // system) + derivatives
                    return makeTable(3, {
                        1.510899999999999e-01,          0,    1.000000000000000e+20,
                        3.000000000000000e-01,          0,                        0,
                        4.000000000000000e-01,          0,                        0,
                        5.000000000000000e-01,          0,                        0,
                        6.000000000000000e-01,          0,                        0,
                        7.000000000000000e-01,    2.0e-02,    2.000000000000000e-01,
                        8.000000000000000e-01,    1.0e-01,    7.999999999999993e-01,
                        9.000000000000000e-01,    3.3e-01,    2.300000000000001e+00,
                        9.600000000000000e-01,    6.0e-01,    4.500000000000004e+00,
                        1.000000000000000e+00,    1.0e+00,    9.999999999999991e+00,
                        1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,
                        1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,
                        1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,
                        1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,
                        1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,
                        1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,
                        1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,
                        1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,
                        1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,
                        1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,
                        1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,
                        1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,
                        1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,
                        1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,
                        1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,
                        1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,
                        1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,
                        1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,
                        1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,
                        1.000000000000000e+20,    1.0e+20,    1.000000000000000e+20,
                    });
                }
            } // GasOil

            namespace OilWater {
                Opm::EclipseState satfuncTables()
                {
                    const auto* input = R"(
RUNSPEC
WATER
OIL

METRIC

DIMENS
  1 1 1 /

TABDIMS
    1    1   30   20    1   20 /

-- =======================================
GRID

DXV
  1 /

DYV
  1 /

DZV
  0.1 /

DEPTHZ
  4*2000.0 /

PERMX
  100.0 /

COPY
  'PERMX' 'PERMY' /
  'PERMX' 'PERMZ' /
/

MULTIPLY
  'PERMZ' 0.1 /
/

PORO
  0.3 /

-- =======================================
PROPS

SWOF
-- SPE 9 Table
     1.510900000000000e-01                         0     1.000000000000000e+00     2.757902917267344e+01
     1.512300000000000e-01                         0     9.999700000000000e-01     2.476527872133143e+01
     1.517400000000000e-01                         0     9.999300000000000e-01     1.778295801053983e+01
     1.524600000000000e-01                         0     9.999100000000000e-01     1.284562231290197e+01
     1.564700000000000e-01                         0     9.995100000000000e-01     5.450995115978905e+00
     1.658500000000000e-01                         0     9.962900000000000e-01     2.758592392996661e+00
     1.783500000000000e-01                         0     9.915900000000000e-01     1.925705711981923e+00
     2.033500000000000e-01     1.000000000000000e-05     9.788300000000000e-01     1.406530487806345e+00
     2.533500000000000e-01     3.000000000000000e-05     9.437300000000000e-01     1.072134759087680e+00
     3.500000000000000e-01     2.800000000000000e-04     8.302300000000000e-01     8.035839625187723e-01
     3.520000000000000e-01     2.292000000000000e-03     8.042770000000000e-01     6.012228359642811e-01
     3.540000000000000e-01     4.304000000000000e-03     7.783260000000000e-01     4.100312162247224e-01
     3.560000000000000e-01     6.316000000000000e-03     7.523740000000000e-01     2.286990994143945e-01
     3.580000000000000e-01     8.328000000000000e-03     7.264220000000000e-01     8.032392246541140e-02
     3.600000000000000e-01     1.034000000000000e-02     7.004700000000000e-01     3.192272626736951e-02
     3.643950000000000e-01     1.554800000000000e-02     6.422580000000000e-01    -3.440483889291011e-02
     3.687900000000000e-01     2.075600000000000e-02     5.840460000000000e-01    -7.853128556918762e-02
     3.700000000000000e-01     2.219000000000000e-02     5.680200000000000e-01    -8.232340208043021e-02
     3.800000000000000e-01     3.589000000000000e-02     4.349800000000000e-01    -1.066618953253145e-01
     4.000000000000000e-01     6.952999999999999e-02     1.714300000000000e-01    -1.105919069824205e-01
     4.334500000000000e-01     8.790000000000001e-02     1.253100000000000e-01    -1.179003497131789e-01
     4.613900000000000e-01     1.049100000000000e-01     9.497999999999999e-02    -1.227266798183968e-01
     4.893200000000000e-01     1.232900000000000e-01     7.053000000000000e-02    -1.282424856529315e-01
     5.172500000000000e-01     1.430300000000000e-01     5.113000000000000e-02    -1.330688157581493e-01
     5.731200000000000e-01     1.865900000000000e-01     2.464000000000000e-02    -1.427214759685850e-01
     6.010600000000000e-01     2.103800000000000e-01     1.619000000000000e-02    -1.468583303444861e-01
     6.569300000000000e-01     2.619000000000000e-01     5.940000000000000e-03    -1.558215148256049e-01
     7.128000000000000e-01     3.186500000000000e-01     1.590000000000000e-03    -1.640952235774069e-01
     8.111100000000000e-01     4.309200000000000e-01     2.000000000000000e-05    -1.792636896223773e-01
     8.814900000000000e-01     4.900000000000000e-01                         0    -1.896058255621299e-01 /

DENSITY
  853.0  1014.0  0.75 /

END
)";

                    const auto deck = Opm::Deck{
                        Opm::Parser{}.parseString(input)
                    };

                    return Opm::EclipseState{deck};
                }

                std::vector<double> expect_SOFN()
                {
                    return makeTable(3, {
                        1.185100000000000e-01,                        0,    1.000000000000000e+20,
                        1.888900000000000e-01,    2.000000000000000e-05,    2.841716396703610e-04,
                        2.872000000000000e-01,    1.590000000000000e-03,    1.596989116061438e-02,
                        3.430700000000000e-01,    5.940000000000000e-03,    7.785931626991233e-02,
                        3.989400000000000e-01,    1.619000000000000e-02,    1.834616073026670e-01,
                        4.268800000000000e-01,    2.464000000000000e-02,    3.024337866857543e-01,
                        4.827500000000000e-01,    5.113000000000000e-02,    4.741363880436731e-01,
                        5.106800000000000e-01,    7.053000000000000e-02,    6.945936269244535e-01,
                        5.386100000000000e-01,    9.497999999999999e-02,    8.754027926960254e-01,
                        5.665500000000000e-01,    1.253100000000000e-01,    1.085540443808162e+00,
                        6.000000000000000e-01,    1.714300000000000e-01,    1.378774289985053e+00,
                        6.200000000000000e-01,    4.349800000000000e-01,    1.317749999999999e+01,
                        6.300000000000000e-01,    5.680200000000000e-01,    1.330399999999999e+01,
                        6.312100000000000e-01,    5.840460000000000e-01,    1.324462809917306e+01,
                        6.356050000000000e-01,    6.422580000000000e-01,    1.324505119453948e+01,
                        6.400000000000000e-01,    7.004700000000000e-01,    1.324505119453914e+01,
                        6.420000000000000e-01,    7.264220000000000e-01,    1.297599999999998e+01,
                        6.440000000000000e-01,    7.523740000000000e-01,    1.297599999999998e+01,
                        6.460000000000000e-01,    7.783260000000000e-01,    1.297599999999998e+01,
                        6.480000000000000e-01,    8.042770000000000e-01,    1.297550000000002e+01,
                        6.500000000000000e-01,    8.302300000000000e-01,    1.297649999999999e+01,
                        7.466500000000000e-01,    9.437300000000000e-01,    1.174340403517847e+00,
                        7.966500000000000e-01,    9.788300000000000e-01,    7.020000000000013e-01,
                        8.216500000000000e-01,    9.915900000000000e-01,    5.103999999999993e-01,
                        8.341499999999999e-01,    9.962900000000000e-01,    3.760000000000043e-01,
                        8.435300000000000e-01,    9.995100000000000e-01,    3.432835820895503e-01,
                        8.475400000000000e-01,    9.999100000000000e-01,    9.975062344138656e-02,
                        8.482600000000000e-01,    9.999300000000000e-01,    2.777777777780348e-02,
                        8.487700000000000e-01,    9.999700000000000e-01,    7.843137254909643e-02,
                        8.489100000000001e-01,    1.000000000000000e+00,    2.142857142854877e-01,
                    });
                }

                std::vector<double> expect_SWFN()
                {
                    // Columns 1, 2, 4 (+ derivatives) of SWOF
                    return makeTable(5, {
                        1.51090e-01,                        0,    2.757902917267344e+01,    1.000000000000000e+20,    1.000000000000000e+20,
                        1.51230e-01,                        0,    2.476527872133143e+01,                        0,   -2.009821750958577e+04,
                        1.51740e-01,                        0,    1.778295801053983e+01,                        0,   -1.369082492312075e+04,
                        1.52460e-01,                        0,    1.284562231290197e+01,                        0,   -6.857410691163744e+03,
                        1.56470e-01,                        0,    5.450995115978905e+00,                        0,   -1.844046682524494e+03,
                        1.65850e-01,                        0,    2.758592392996661e+00,                        0,   -2.870365376313702e+02,
                        1.78350e-01,                        0,    1.925705711981923e+00,                        0,   -6.663093448117903e+01,
                        2.03350e-01,    1.000000000000000e-05,    1.406530487806345e+00,    4.000000000000000e-04,   -2.076700896702310e+01,
                        2.53350e-01,    3.000000000000000e-05,    1.072134759087680e+00,    4.000000000000000e-04,   -6.687914574373308e+00,
                        3.50000e-01,    2.800000000000000e-04,    8.035839625187723e-01,    2.586652871184700e-03,   -2.778590756015570e+00,
                        3.52000e-01,    2.292000000000000e-03,    6.012228359642811e-01,    1.006000000000000e+00,   -1.011805632772457e+02,
                        3.54000e-01,    4.304000000000000e-03,    4.100312162247224e-01,    1.006000000000000e+00,   -9.559580986977932e+01,
                        3.56000e-01,    6.316000000000000e-03,    2.286990994143945e-01,    1.006000000000000e+00,   -9.066605840516394e+01,
                        3.58000e-01,    8.328000000000000e-03,    8.032392246541140e-02,    1.006000000000000e+00,   -7.418758847449155e+01,
                        3.60000e-01,    1.034000000000000e-02,    3.192272626736951e-02,    1.006000000000000e+00,   -2.420059809902094e+01,
                        3.64395e-01,    1.554800000000000e-02,   -3.440483889291011e-02,    1.184982935153600e+00,   -1.509159616843634e+01,
                        3.68790e-01,    2.075600000000000e-02,   -7.853128556918762e-02,    1.184982935153600e+00,   -1.004014713908486e+01,
                        3.70000e-01,    2.219000000000000e-02,   -8.232340208043021e-02,    1.185123966942200e+00,   -3.133980587803838e+00,
                        3.80000e-01,    3.589000000000000e-02,   -1.066618953253145e-01,    1.370000000000000e+00,   -2.433849324488431e+00,
                        4.00000e-01,    6.952999999999999e-02,   -1.105919069824205e-01,    1.682000000000000e+00,   -1.965005828552983e-01,
                        4.33450e-01,    8.790000000000001e-02,   -1.179003497131789e-01,    5.491778774290000e-01,   -2.184885719210279e-01,
                        4.61390e-01,    1.049100000000000e-01,   -1.227266798183968e-01,    6.088045812455301e-01,   -1.727390875167428e-01,
                        4.89320e-01,    1.232900000000000e-01,   -1.282424856529315e-01,    6.580737558181200e-01,   -1.974867824752831e-01,
                        5.17250e-01,    1.430300000000000e-01,   -1.330688157581493e-01,    7.067669172932300e-01,   -1.728009346658736e-01,
                        5.73120e-01,    1.865900000000000e-01,   -1.427214759685850e-01,    7.796670843028500e-01,   -1.727700055563935e-01,
                        6.01060e-01,    2.103800000000000e-01,   -1.468583303444861e-01,    8.514674302075900e-01,   -1.480620750143510e-01,
                        6.56930e-01,    2.619000000000000e-01,   -1.558215148256049e-01,    9.221406837300899e-01,   -1.604292908737955e-01,
                        7.12800e-01,    3.186500000000000e-01,   -1.640952235774069e-01,    1.015750850187900e+00,   -1.480885761911974e-01,
                        8.11110e-01,    4.309200000000000e-01,   -1.792636896223773e-01,    1.141999796561900e+00,   -1.542921986061490e-01,
                        8.81490e-01,    4.900000000000000e-01,   -1.896058255621299e-01,    8.394430235862500e-01,   -1.469470863846619e-01,
                    });
                }
            } // OilWater
        } // TwoPhase

        namespace ThreePhase {
            Opm::EclipseState satfuncTables()
            {
                const auto* input = R"(
RUNSPEC
WATER
OIL
GAS

METRIC

DIMENS
  1 1 1 /

TABDIMS
    1    1   30   20    1   20 /

-- =======================================
GRID

DXV
  1 /

DYV
  1 /

DZV
  0.1 /

DEPTHZ
  4*2000.0 /

PERMX
  100.0 /

COPY
  'PERMX' 'PERMY' /
  'PERMX' 'PERMZ' /
/

MULTIPLY
  'PERMZ' 0.1 /
/

PORO
  0.3 /

-- =======================================
PROPS

SWOF
-- SPE 9 Table
     1.510900000000000e-01                         0     1.000000000000000e+00     2.757902917267344e+01
     1.512300000000000e-01                         0     9.999700000000000e-01     2.476527872133143e+01
     1.517400000000000e-01                         0     9.999300000000000e-01     1.778295801053983e+01
     1.524600000000000e-01                         0     9.999100000000000e-01     1.284562231290197e+01
     1.564700000000000e-01                         0     9.995100000000000e-01     5.450995115978905e+00
     1.658500000000000e-01                         0     9.962900000000000e-01     2.758592392996661e+00
     1.783500000000000e-01                         0     9.915900000000000e-01     1.925705711981923e+00
     2.033500000000000e-01     1.000000000000000e-05     9.788300000000000e-01     1.406530487806345e+00
     2.533500000000000e-01     3.000000000000000e-05     9.437300000000000e-01     1.072134759087680e+00
     3.500000000000000e-01     2.800000000000000e-04     8.302300000000000e-01     8.035839625187723e-01
     3.520000000000000e-01     2.292000000000000e-03     8.042770000000000e-01     6.012228359642811e-01
     3.540000000000000e-01     4.304000000000000e-03     7.783260000000000e-01     4.100312162247224e-01
     3.560000000000000e-01     6.316000000000000e-03     7.523740000000000e-01     2.286990994143945e-01
     3.580000000000000e-01     8.328000000000000e-03     7.264220000000000e-01     8.032392246541140e-02
     3.600000000000000e-01     1.034000000000000e-02     7.004700000000000e-01     3.192272626736951e-02
     3.643950000000000e-01     1.554800000000000e-02     6.422580000000000e-01    -3.440483889291011e-02
     3.687900000000000e-01     2.075600000000000e-02     5.840460000000000e-01    -7.853128556918762e-02
     3.700000000000000e-01     2.219000000000000e-02     5.680200000000000e-01    -8.232340208043021e-02
     3.800000000000000e-01     3.589000000000000e-02     4.349800000000000e-01    -1.066618953253145e-01
     4.000000000000000e-01     6.952999999999999e-02     1.714300000000000e-01    -1.105919069824205e-01
     4.334500000000000e-01     8.790000000000001e-02     1.253100000000000e-01    -1.179003497131789e-01
     4.613900000000000e-01     1.049100000000000e-01     9.497999999999999e-02    -1.227266798183968e-01
     4.893200000000000e-01     1.232900000000000e-01     7.053000000000000e-02    -1.282424856529315e-01
     5.172500000000000e-01     1.430300000000000e-01     5.113000000000000e-02    -1.330688157581493e-01
     5.731200000000000e-01     1.865900000000000e-01     2.464000000000000e-02    -1.427214759685850e-01
     6.010600000000000e-01     2.103800000000000e-01     1.619000000000000e-02    -1.468583303444861e-01
     6.569300000000000e-01     2.619000000000000e-01     5.940000000000000e-03    -1.558215148256049e-01
     7.128000000000000e-01     3.186500000000000e-01     1.590000000000000e-03    -1.640952235774069e-01
     8.111100000000000e-01     4.309200000000000e-01     2.000000000000000e-05    -1.792636896223773e-01
     8.814900000000000e-01     4.900000000000000e-01                         0    -1.896058255621299e-01 /

SGOF
-- SPE 9 Table
                         0                         0     1.000000000000000e+00                         0
     4.000000000000000e-02                         0     6.000000000000000e-01     1.378951458633672e-02
     1.000000000000000e-01     2.200000000000000e-02     3.300000000000000e-01     3.447378646584180e-02
     2.000000000000000e-01     1.000000000000000e-01     1.000000000000000e-01     6.894757293168360e-02
     3.000000000000000e-01     2.400000000000000e-01     2.000000000000000e-02     1.034213593975254e-01
     4.000000000000000e-01     3.400000000000000e-01                         0     1.378951458633672e-01
     5.000000000000000e-01     4.200000000000000e-01                         0     1.723689323292090e-01
     6.000000000000000e-01     5.000000000000000e-01                         0     2.068427187950508e-01
     7.000000000000000e-01     8.125000000000000e-01                         0     2.413165052608926e-01
     8.489100000000001e-01     9.635000000000000e-01                         0     2.633797285990314e-01 /

DENSITY
  853.0  1014.0  0.75 /

END
)";

                const auto deck = Opm::Deck{
                    Opm::Parser{}.parseString(input)
                };

                return Opm::EclipseState{deck};
            }

            std::vector<double> expect_SGFN()
            {
                // Columns 1, 2, 4 (+ derivatives) of SGOF
                return makeTable(5, {
                             0,            0,                        0,    1.000000000000000e+20,    1.000000000000000e+20,
                    4.0000e-02,            0,    1.378951458633672e-02,                        0,    3.447378646584180e-01,
                    1.0000e-01,    2.200e-02,    3.447378646584180e-02,    3.666666666666666e-01,    3.447378646584180e-01,
                    2.0000e-01,    1.000e-01,    6.894757293168360e-02,    7.800000000000001e-01,    3.447378646584180e-01,
                    3.0000e-01,    2.400e-01,    1.034213593975254e-01,    1.400000000000000e+00,    3.447378646584180e-01,
                    4.0000e-01,    3.400e-01,    1.378951458633672e-01,    1.000000000000000e+00,    3.447378646584179e-01,
                    5.0000e-01,    4.200e-01,    1.723689323292090e-01,    7.999999999999998e-01,    3.447378646584180e-01,
                    6.0000e-01,    5.000e-01,    2.068427187950508e-01,    8.000000000000004e-01,    3.447378646584180e-01,
                    7.0000e-01,    8.125e-01,    2.413165052608926e-01,    3.125000000000001e+00,    3.447378646584180e-01,
                    8.4891e-01,    9.635e-01,    2.633797285990314e-01,    1.014035323349674e+00,    1.481648199458648e-01,
                    1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.0000e+20,    1.000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                });
            }

            std::vector<double> expect_SOFN()
            {
                // Column 1 from SGOF merged with column 1 from SWOF, Column 3 from
                // SWOF (+ piecewise linear interp), Column 3 from SGOF (+piecewise
                // linear interp) + derivatives of those.
                return makeTable(5, {
                                        0,                        0,                        0,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.185100000000000e-01,                        0,                        0,                        0,                        0,
                    1.489100000000001e-01,    8.638817845978999e-06,                        0,    2.841716396703609e-04,                        0,
                    1.888900000000000e-01,    2.000000000000000e-05,                        0,    2.841716396703610e-04,                        0,
                    2.489100000000001e-01,    9.785128674600764e-04,                        0,    1.596989116061438e-02,                        0,
                    2.872000000000000e-01,    1.590000000000000e-03,                        0,    1.596989116061438e-02,                        0,
                    3.430700000000000e-01,    5.940000000000000e-03,                        0,    7.785931626991233e-02,                        0,
                    3.489100000000001e-01,    7.011415786647587e-03,                        0,    1.834616073026669e-01,                        0,
                    3.989400000000000e-01,    1.619000000000000e-02,                        0,    1.834616073026670e-01,                        0,
                    4.268800000000000e-01,    2.464000000000000e-02,                        0,    3.024337866857543e-01,                        0,
                    4.489100000000000e-01,    3.508522462860211e-02,                        0,    4.741363880436730e-01,                        0,
                    4.827500000000000e-01,    5.113000000000000e-02,    6.767999999999998e-03,    4.741363880436731e-01,    2.000000000000000e-01,
                    5.106800000000000e-01,    7.053000000000000e-02,    1.235400000000000e-02,    6.945936269244535e-01,    2.000000000000000e-01,
                    5.386100000000000e-01,    9.497999999999999e-02,    1.794000000000000e-02,    8.754027926960254e-01,    2.000000000000001e-01,
                    5.489100000000000e-01,    1.061610665712240e-01,    2.000000000000000e-02,    1.085540443808162e+00,    2.000000000000001e-01,
                    5.665500000000000e-01,    1.253100000000000e-01,    3.411199999999998e-02,    1.085540443808162e+00,    7.999999999999990e-01,
                    6.000000000000000e-01,    1.714300000000000e-01,    6.087199999999994e-02,    1.378774289985053e+00,    7.999999999999994e-01,
                    6.200000000000000e-01,    4.349800000000000e-01,    7.687199999999994e-02,    1.317749999999999e+01,    7.999999999999993e-01,
                    6.300000000000000e-01,    5.680200000000000e-01,    8.487199999999995e-02,    1.330399999999999e+01,    8.000000000000000e-01,
                    6.312100000000000e-01,    5.840460000000000e-01,    8.583999999999999e-02,    1.324462809917306e+01,    8.000000000000023e-01,
                    6.356050000000000e-01,    6.422580000000000e-01,    8.935599999999992e-02,    1.324505119453948e+01,    7.999999999999987e-01,
                    6.400000000000000e-01,    7.004700000000000e-01,    9.287199999999994e-02,    1.324505119453914e+01,    7.999999999999975e-01,
                    6.420000000000000e-01,    7.264220000000000e-01,    9.447199999999994e-02,    1.297599999999998e+01,    8.000000000000014e-01,
                    6.440000000000000e-01,    7.523740000000000e-01,    9.607199999999995e-02,    1.297599999999998e+01,    8.000000000000014e-01,
                    6.460000000000000e-01,    7.783260000000000e-01,    9.767199999999995e-02,    1.297599999999998e+01,    8.000000000000014e-01,
                    6.480000000000000e-01,    8.042770000000000e-01,    9.927199999999994e-02,    1.297550000000002e+01,    7.999999999999945e-01,
                    6.489100000000001e-01,    8.160856150000010e-01,    1.000000000000000e-01,    1.297649999999996e+01,    8.000000000000000e-01,
                    6.500000000000000e-01,    8.302300000000000e-01,    1.025069999999998e-01,    1.297650000000002e+01,    2.300000000000002e+00,
                    7.466500000000000e-01,    9.437300000000000e-01,    3.248019999999999e-01,    1.174340403517847e+00,    2.300000000000000e+00,
                    7.489100000000001e-01,    9.453165200000000e-01,    3.300000000000000e-01,    7.020000000000034e-01,    2.300000000000000e+00,
                    7.966500000000000e-01,    9.788300000000000e-01,    5.448299999999997e-01,    7.020000000000013e-01,    4.500000000000004e+00,
                    8.089100000000000e-01,    9.850875040000000e-01,    6.000000000000000e-01,    5.104000000000000e-01,    4.500000000000004e+00,
                    8.216500000000000e-01,    9.915900000000000e-01,    7.273999999999996e-01,    5.103999999999986e-01,    9.999999999999991e+00,
                    8.341499999999999e-01,    9.962900000000000e-01,    8.523999999999990e-01,    3.760000000000043e-01,    9.999999999999991e+00,
                    8.435300000000000e-01,    9.995100000000000e-01,    9.461999999999995e-01,    3.432835820895503e-01,    9.999999999999988e+00,
                    8.475400000000000e-01,    9.999100000000000e-01,    9.862999999999991e-01,    9.975062344138656e-02,    1.000000000000000e+01,
                    8.482600000000000e-01,    9.999300000000000e-01,    9.934999999999996e-01,    2.777777777780348e-02,    1.000000000000000e+01,
                    8.487700000000000e-01,    9.999700000000000e-01,    9.985999999999997e-01,    7.843137254909643e-02,    1.000000000000000e+01,
                    8.489100000000001e-01,    1.000000000000000e+00,    1.000000000000000e+00,    2.142857142854877e-01,    1.000000000000000e+01,
                    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,    1.000000000000000e+20,
                });
            }

            std::vector<double> expect_SWFN()
            {
                // Columns 1, 2, 4 (+ derivatives) of SWOF
                return makeTable(5, {
                    1.51090e-01,                        0,    2.757902917267344e+01,    1.000000000000000e+20,    1.000000000000000e+20,
                    1.51230e-01,                        0,    2.476527872133143e+01,                        0,   -2.009821750958577e+04,
                    1.51740e-01,                        0,    1.778295801053983e+01,                        0,   -1.369082492312075e+04,
                    1.52460e-01,                        0,    1.284562231290197e+01,                        0,   -6.857410691163744e+03,
                    1.56470e-01,                        0,    5.450995115978905e+00,                        0,   -1.844046682524494e+03,
                    1.65850e-01,                        0,    2.758592392996661e+00,                        0,   -2.870365376313702e+02,
                    1.78350e-01,                        0,    1.925705711981923e+00,                        0,   -6.663093448117903e+01,
                    2.03350e-01,    1.000000000000000e-05,    1.406530487806345e+00,    4.000000000000000e-04,   -2.076700896702310e+01,
                    2.53350e-01,    3.000000000000000e-05,    1.072134759087680e+00,    4.000000000000000e-04,   -6.687914574373308e+00,
                    3.50000e-01,    2.800000000000000e-04,    8.035839625187723e-01,    2.586652871184700e-03,   -2.778590756015570e+00,
                    3.52000e-01,    2.292000000000000e-03,    6.012228359642811e-01,    1.006000000000000e+00,   -1.011805632772457e+02,
                    3.54000e-01,    4.304000000000000e-03,    4.100312162247224e-01,    1.006000000000000e+00,   -9.559580986977932e+01,
                    3.56000e-01,    6.316000000000000e-03,    2.286990994143945e-01,    1.006000000000000e+00,   -9.066605840516394e+01,
                    3.58000e-01,    8.328000000000000e-03,    8.032392246541140e-02,    1.006000000000000e+00,   -7.418758847449155e+01,
                    3.60000e-01,    1.034000000000000e-02,    3.192272626736951e-02,    1.006000000000000e+00,   -2.420059809902094e+01,
                    3.64395e-01,    1.554800000000000e-02,   -3.440483889291011e-02,    1.184982935153600e+00,   -1.509159616843634e+01,
                    3.68790e-01,    2.075600000000000e-02,   -7.853128556918762e-02,    1.184982935153600e+00,   -1.004014713908486e+01,
                    3.70000e-01,    2.219000000000000e-02,   -8.232340208043021e-02,    1.185123966942200e+00,   -3.133980587803838e+00,
                    3.80000e-01,    3.589000000000000e-02,   -1.066618953253145e-01,    1.370000000000000e+00,   -2.433849324488431e+00,
                    4.00000e-01,    6.952999999999999e-02,   -1.105919069824205e-01,    1.682000000000000e+00,   -1.965005828552983e-01,
                    4.33450e-01,    8.790000000000001e-02,   -1.179003497131789e-01,    5.491778774290000e-01,   -2.184885719210279e-01,
                    4.61390e-01,    1.049100000000000e-01,   -1.227266798183968e-01,    6.088045812455301e-01,   -1.727390875167428e-01,
                    4.89320e-01,    1.232900000000000e-01,   -1.282424856529315e-01,    6.580737558181200e-01,   -1.974867824752831e-01,
                    5.17250e-01,    1.430300000000000e-01,   -1.330688157581493e-01,    7.067669172932300e-01,   -1.728009346658736e-01,
                    5.73120e-01,    1.865900000000000e-01,   -1.427214759685850e-01,    7.796670843028500e-01,   -1.727700055563935e-01,
                    6.01060e-01,    2.103800000000000e-01,   -1.468583303444861e-01,    8.514674302075900e-01,   -1.480620750143510e-01,
                    6.56930e-01,    2.619000000000000e-01,   -1.558215148256049e-01,    9.221406837300899e-01,   -1.604292908737955e-01,
                    7.12800e-01,    3.186500000000000e-01,   -1.640952235774069e-01,    1.015750850187900e+00,   -1.480885761911974e-01,
                    8.11110e-01,    4.309200000000000e-01,   -1.792636896223773e-01,    1.141999796561900e+00,   -1.542921986061490e-01,
                    8.81490e-01,    4.900000000000000e-01,   -1.896058255621299e-01,    8.394430235862500e-01,   -1.469470863846619e-01,
                });
            }
        } // ThreePhase
    } // SPE9
} // Anonymous namespace

// #####################################################################

BOOST_AUTO_TEST_SUITE (Two_Phase)

BOOST_AUTO_TEST_CASE (Oil_Water_Family_One)
{
    const auto es = SPE9::TwoPhase::OilWater::satfuncTables();

    auto tables = Opm::Tables{ es.getUnits() };
    tables.addSatFunc(es);

    const auto& tabdims = tables.tabdims();
    const auto& tab     = tables.tab();

    // SOFN
    {
        const auto ibsofn = tabdims[ Ix::SofnTableStart ] - 1;
        const auto nssofn = tabdims[ Ix::SofnNumSatNodes ];
        const auto ntsofn = tabdims[ Ix::SofnNumTables ];
        const auto ncol   = 3;

        const auto sofn = std::vector<double> {
            &tab[ ibsofn ] + 0,
            &tab[ ibsofn ] + ntsofn*nssofn*ncol
        };

        BOOST_CHECK_EQUAL(nssofn, 30);
        BOOST_CHECK_EQUAL(ntsofn,  1);

        check_is_close(sofn, SPE9::TwoPhase::OilWater::expect_SOFN());
    }

    // SWFN
    {
        const auto ibswfn = tabdims[ Ix::SwfnTableStart ] - 1;
        const auto nsswfn = tabdims[ Ix::SwfnNumSatNodes ];
        const auto ntswfn = tabdims[ Ix::SwfnNumTables ];
        const auto ncol   = 5;

        const auto swfn = std::vector<double> {
            &tab[ ibswfn ] + 0,
            &tab[ ibswfn ] + ntswfn*nsswfn*ncol
        };

        BOOST_CHECK_EQUAL(nsswfn, 30);
        BOOST_CHECK_EQUAL(ntswfn,  1);

        check_is_close(swfn, SPE9::TwoPhase::OilWater::expect_SWFN());
    }
}

BOOST_AUTO_TEST_CASE (Oil_Water_Family_Two)
{
    const auto es = SPE1::TwoPhase::OilWater::satfuncTables();

    auto tables = Opm::Tables{ es.getUnits() };
    tables.addSatFunc(es);

    const auto& tabdims = tables.tabdims();
    const auto& tab     = tables.tab();

    // SOFN
    {
        const auto ibsofn = tabdims[ Ix::SofnTableStart ] - 1;
        const auto nssofn = tabdims[ Ix::SofnNumSatNodes ];
        const auto ntsofn = tabdims[ Ix::SofnNumTables ];
        const auto ncol   = 3;

        const auto sofn = std::vector<double> {
            &tab[ ibsofn ] + 0,
            &tab[ ibsofn ] + ntsofn*nssofn*ncol
        };

        BOOST_CHECK_EQUAL(nssofn, 20);
        BOOST_CHECK_EQUAL(ntsofn,  1);

        check_is_close(sofn, SPE1::TwoPhase::OilWater::expect_SOFN());
    }

    // SWFN
    {
        const auto ibswfn = tabdims[ Ix::SwfnTableStart ] - 1;
        const auto nsswfn = tabdims[ Ix::SwfnNumSatNodes ];
        const auto ntswfn = tabdims[ Ix::SwfnNumTables ];
        const auto ncol   = 5;

        const auto swfn = std::vector<double> {
            &tab[ ibswfn ] + 0,
            &tab[ ibswfn ] + ntswfn*nsswfn*ncol
        };

        BOOST_CHECK_EQUAL(nsswfn, 20);
        BOOST_CHECK_EQUAL(ntswfn,  1);

        check_is_close(swfn, SPE1::TwoPhase::OilWater::expect_SWFN());
    }
}

BOOST_AUTO_TEST_CASE (Gas_Oil_Familiy_One)
{
    const auto es = SPE9::TwoPhase::GasOil::satfuncTables();

    auto tables = Opm::Tables{ es.getUnits() };
    tables.addSatFunc(es);

    const auto& tabdims = tables.tabdims();
    const auto& tab     = tables.tab();

    // SGFN
    {
        const auto ibsgfn = tabdims[ Ix::SgfnTableStart ] - 1;
        const auto nssgfn = tabdims[ Ix::SgfnNumSatNodes ];
        const auto ntsgfn = tabdims[ Ix::SgfnNumTables ];
        const auto ncol   = 5;

        const auto sgfn = std::vector<double> {
            &tab[ ibsgfn ] + 0,
            &tab[ ibsgfn ] + ntsgfn*nssgfn*ncol
        };

        BOOST_CHECK_EQUAL(nssgfn, 30);
        BOOST_CHECK_EQUAL(ntsgfn,  1);

        check_is_close(sgfn, SPE9::TwoPhase::GasOil::expect_SGFN());
    }

    // SOFN
    {
        const auto ibsofn = tabdims[ Ix::SofnTableStart ] - 1;
        const auto nssofn = tabdims[ Ix::SofnNumSatNodes ];
        const auto ntsofn = tabdims[ Ix::SofnNumTables ];
        const auto ncol   = 3;

        const auto sofn = std::vector<double> {
            &tab[ ibsofn ] + 0,
            &tab[ ibsofn ] + ntsofn*nssofn*ncol
        };

        BOOST_CHECK_EQUAL(nssofn, 30);
        BOOST_CHECK_EQUAL(ntsofn,  1);

        check_is_close(sofn, SPE9::TwoPhase::GasOil::expect_SOFN());
    }
}

BOOST_AUTO_TEST_CASE (Gas_Oil_Familiy_Two)
{
    const auto es = SPE1::TwoPhase::GasOil::satfuncTables();

    auto tables = Opm::Tables{ es.getUnits() };
    tables.addSatFunc(es);

    const auto& tabdims = tables.tabdims();
    const auto& tab     = tables.tab();

    // SGFN
    {
        const auto ibsgfn = tabdims[ Ix::SgfnTableStart ] - 1;
        const auto nssgfn = tabdims[ Ix::SgfnNumSatNodes ];
        const auto ntsgfn = tabdims[ Ix::SgfnNumTables ];
        const auto ncol   = 5;

        const auto sgfn = std::vector<double> {
            &tab[ ibsgfn ] + 0,
            &tab[ ibsgfn ] + ntsgfn*nssgfn*ncol
        };

        BOOST_CHECK_EQUAL(nssgfn, 20);
        BOOST_CHECK_EQUAL(ntsgfn,  1);

        check_is_close(sgfn, SPE1::TwoPhase::GasOil::expect_SGFN());
    }

    // SOFN
    {
        const auto ibsofn = tabdims[ Ix::SofnTableStart ] - 1;
        const auto nssofn = tabdims[ Ix::SofnNumSatNodes ];
        const auto ntsofn = tabdims[ Ix::SofnNumTables ];
        const auto ncol   = 3;

        const auto sofn = std::vector<double> {
            &tab[ ibsofn ] + 0,
            &tab[ ibsofn ] + ntsofn*nssofn*ncol
        };

        BOOST_CHECK_EQUAL(nssofn, 20);
        BOOST_CHECK_EQUAL(ntsofn,  1);

        check_is_close(sofn, SPE1::TwoPhase::GasOil::expect_SOFN());
    }
}

BOOST_AUTO_TEST_SUITE_END ()

// #####################################################################

BOOST_AUTO_TEST_SUITE (Three_Phase)

BOOST_AUTO_TEST_CASE (Serialize_Family_One)
{
    const auto es = SPE9::ThreePhase::satfuncTables();

    auto tables = Opm::Tables{ es.getUnits() };
    tables.addSatFunc(es);

    const auto& tabdims = tables.tabdims();
    const auto& tab     = tables.tab();

    // SGFN
    {
        const auto ibsgfn = tabdims[ Ix::SgfnTableStart ] - 1;
        const auto nssgfn = tabdims[ Ix::SgfnNumSatNodes ];
        const auto ntsgfn = tabdims[ Ix::SgfnNumTables ];
        const auto ncol   = 5;

        const auto sgfn = std::vector<double> {
            &tab[ ibsgfn ] + 0,
            &tab[ ibsgfn ] + ntsgfn*nssgfn*ncol
        };

        BOOST_CHECK_EQUAL(nssgfn, 30);
        BOOST_CHECK_EQUAL(ntsgfn,  1);

        check_is_close(sgfn, SPE9::ThreePhase::expect_SGFN());
    }

    // SOFN
    {
        const auto ibsofn = tabdims[ Ix::SofnTableStart ] - 1;
        const auto nssofn = tabdims[ Ix::SofnNumSatNodes ];
        const auto ntsofn = tabdims[ Ix::SofnNumTables ];
        const auto ncol   = 5;

        const auto sofn = std::vector<double> {
            &tab[ ibsofn ] + 0,
            &tab[ ibsofn ] + ntsofn*nssofn*ncol
        };

        BOOST_CHECK_EQUAL(nssofn, 2 * 30);
        BOOST_CHECK_EQUAL(ntsofn,      1);

        check_is_close(sofn, SPE9::ThreePhase::expect_SOFN());
    }

    // SWFN
    {
        const auto ibswfn = tabdims[ Ix::SwfnTableStart ] - 1;
        const auto nsswfn = tabdims[ Ix::SwfnNumSatNodes ];
        const auto ntswfn = tabdims[ Ix::SwfnNumTables ];
        const auto ncol   = 5;

        const auto swfn = std::vector<double> {
            &tab[ ibswfn ] + 0,
            &tab[ ibswfn ] + ntswfn*nsswfn*ncol
        };

        BOOST_CHECK_EQUAL(nsswfn, 30);
        BOOST_CHECK_EQUAL(ntswfn,  1);

        check_is_close(swfn, SPE9::ThreePhase::expect_SWFN());
    }
}

BOOST_AUTO_TEST_CASE (Serialize_Family_Two)
{
    const auto es = SPE1::ThreePhase::satfuncTables();

    auto tables = Opm::Tables{ es.getUnits() };
    tables.addSatFunc(es);

    const auto& tabdims = tables.tabdims();
    const auto& tab     = tables.tab();

    // SGFN
    {
        const auto ibsgfn = tabdims[ Ix::SgfnTableStart ] - 1;
        const auto nssgfn = tabdims[ Ix::SgfnNumSatNodes ];
        const auto ntsgfn = tabdims[ Ix::SgfnNumTables ];
        const auto ncol   = 5;

        const auto sgfn = std::vector<double> {
            &tab[ ibsgfn ] + 0,
            &tab[ ibsgfn ] + ntsgfn*nssgfn*ncol
        };

        BOOST_CHECK_EQUAL(nssgfn, 20);
        BOOST_CHECK_EQUAL(ntsgfn,  1);

        check_is_close(sgfn, SPE1::ThreePhase::expect_SGFN());
    }

    // SOFN
    {
        const auto ibsofn = tabdims[ Ix::SofnTableStart ] - 1;
        const auto nssofn = tabdims[ Ix::SofnNumSatNodes ];
        const auto ntsofn = tabdims[ Ix::SofnNumTables ];
        const auto ncol   = 5;

        const auto sofn = std::vector<double> {
            &tab[ ibsofn ] + 0,
            &tab[ ibsofn ] + ntsofn*nssofn*ncol
        };

        BOOST_CHECK_EQUAL(nssofn, 20);
        BOOST_CHECK_EQUAL(ntsofn,  1);

        check_is_close(sofn, SPE1::ThreePhase::expect_SOFN());
    }

    // SWFN
    {
        const auto ibswfn = tabdims[ Ix::SwfnTableStart ] - 1;
        const auto nsswfn = tabdims[ Ix::SwfnNumSatNodes ];
        const auto ntswfn = tabdims[ Ix::SwfnNumTables ];
        const auto ncol   = 5;

        const auto swfn = std::vector<double> {
            &tab[ ibswfn ] + 0,
            &tab[ ibswfn ] + ntswfn*nsswfn*ncol
        };

        BOOST_CHECK_EQUAL(nsswfn, 20);
        BOOST_CHECK_EQUAL(ntswfn,  1);

        check_is_close(swfn, SPE1::ThreePhase::expect_SWFN());
    }
}

BOOST_AUTO_TEST_CASE (Tabdims_Mismatch)
{
    const auto es = SPE1::ThreePhase::satfuncTablesTabDimsMismatch();

    auto tables = Opm::Tables{ es.getUnits() };
    tables.addSatFunc(es);

    const auto& tabdims = tables.tabdims();
    const auto& tab     = tables.tab();

    // SGFN
    {
        const auto ibsgfn = tabdims[ Ix::SgfnTableStart ] - 1;
        const auto nssgfn = tabdims[ Ix::SgfnNumSatNodes ];
        const auto ntsgfn = tabdims[ Ix::SgfnNumTables ];
        const auto ncol   = 5;

        const auto sgfn = std::vector<double> {
            &tab[ ibsgfn ] + 0,
            &tab[ ibsgfn ] + ntsgfn*nssgfn*ncol
        };

        BOOST_CHECK_EQUAL(nssgfn, 15);
        BOOST_CHECK_EQUAL(ntsgfn,  1);

        check_is_close(sgfn, SPE1::ThreePhase::expect_SGFN_TabDimsMismatch());
    }

    // SOFN
    {
        const auto ibsofn = tabdims[ Ix::SofnTableStart ] - 1;
        const auto nssofn = tabdims[ Ix::SofnNumSatNodes ];
        const auto ntsofn = tabdims[ Ix::SofnNumTables ];
        const auto ncol   = 5;

        const auto sofn = std::vector<double> {
            &tab[ ibsofn ] + 0,
            &tab[ ibsofn ] + ntsofn*nssofn*ncol
        };

        BOOST_CHECK_EQUAL(nssofn, 2 * 15);
        BOOST_CHECK_EQUAL(ntsofn,      1);

        check_is_close(sofn, SPE1::ThreePhase::expect_SOFN_TabDimsMismatch());
    }

    // SWFN
    {
        const auto ibswfn = tabdims[ Ix::SwfnTableStart ] - 1;
        const auto nsswfn = tabdims[ Ix::SwfnNumSatNodes ];
        const auto ntswfn = tabdims[ Ix::SwfnNumTables ];
        const auto ncol   = 5;

        const auto swfn = std::vector<double> {
            &tab[ ibswfn ] + 0,
            &tab[ ibswfn ] + ntswfn*nsswfn*ncol
        };

        BOOST_CHECK_EQUAL(nsswfn, 15);
        BOOST_CHECK_EQUAL(ntswfn,  1);

        check_is_close(swfn, SPE1::ThreePhase::expect_SWFN_TabDimsMismatch());
    }
}

BOOST_AUTO_TEST_SUITE_END ()

// #####################################################################

BOOST_AUTO_TEST_SUITE (PVTTables)

namespace {
    Opm::EclipseState parse(const std::string& rspec,
                            const std::string& props)
    {
        return Opm::EclipseState{
            Opm::Parser{}.parseString(rspec + R"(GRID
INIT

DXV
  10*200 /

DYV
  10*200 /

DZV
  10*25 /

TOPS
  100*2500 /

PORO
  1000*0.3 /

PERMX
  1000*100 /

COPY
  'PERMX' 'PERMY' /
  'PERMX' 'PERMZ' /
/

MULTIPLY
  'PERMZ' 0.1 /
/

PROPS
)" + props + R"(
END
)") };
    }
}

BOOST_AUTO_TEST_SUITE (Gas)

BOOST_AUTO_TEST_CASE (PVDG_Regular)
{
    const auto rspec = std::string { R"(RUNSPEC
DIMENS
  10 10 10 /

TITLE
  Test PVDG Output

GAS

FIELD

TABDIMS
-- NTSFUN  NTPVT  NSSFUN  NPPVT  NTFIP  NRPVT
   1*      2      1*      16     1*     1*
/
)"  };

    const auto props = std::string { R"(
PVDG
  14.7  166.666  0.0080
 264.7   12.093  0.0096
 514.7    6.274  0.0112
1014.7    3.197  0.0140
2014.7    1.614  0.0189
2514.7    1.294  0.0208
3014.7    1.080  0.0228
4014.7    0.811  0.0268
5014.7    0.649  0.0309
9014.7    0.386  0.0470 /
 400.0    5.900  0.0130
 800.0    2.950  0.0135
1200.0    1.960  0.0140
1600.0    1.470  0.0145
2000.0    1.180  0.0150
2400.0    0.980  0.0155
2800.0    0.840  0.0160
3200.0    0.740  0.0165
3600.0    0.650  0.0170
4000.0    0.590  0.0175
4400.0    0.540  0.0180
4800.0    0.490  0.0185
5200.0    0.450  0.0190
5600.0    0.420  0.0195 /
)"  };

    const auto es = parse(rspec, props);

    auto tables = ::Opm::Tables(es.getUnits());
    tables.addPVTTables(es);

    const auto& tabdims = tables.tabdims();
    const auto& tab     = tables.tab();

    const auto ibpvtg = tabdims[ Ix::PvtgMainStart ] - 1;
    const auto nppvtg = tabdims[ Ix::NumPvtgPressNodes ];
    const auto ntpvtg = tabdims[ Ix::NumPvtgTables ];
    const auto ncol   = 5;

    // Pg table defaulted
    BOOST_CHECK_EQUAL(tabdims[Ix::PvtgPressStart], 1);
    BOOST_CHECK_EQUAL(tabdims[Ix::NumPvtgCompNodes], 1);

    BOOST_CHECK_EQUAL(nppvtg, 16);
    BOOST_CHECK_EQUAL(ntpvtg,  2);

    const auto pvdg = std::vector<double> {
        &tab[ ibpvtg ] + 0,
        &tab[ ibpvtg ] + ntpvtg*nppvtg*ncol
    };

    const auto expect_pvdg = makeTable(5, {
        // Pg                     1/Bg                      1/(Bg*mu_g)               d(1/Bg)/dPg               d(1/(Bg*mu_g))/dPg
        //
        // Table 1 (10 pressure nodes)
        1.470000000000000e+01,    6.000024000096002e-03,    7.500030000120003e-01,    2.000000000000000e+20,    2.000000000000000e+20,
        2.647000000000000e+02,    8.269246671628215e-02,    8.613798616279391e+00,    3.067697708647446e-04,    3.145518246506956e-02,
        5.147000000000000e+02,    1.593879502709595e-01,    1.423106698847853e+01,    3.067819342187094e-04,    2.246907348879655e-02,
        1.014700000000000e+03,    3.127932436659369e-01,    2.234237454756692e+01,    3.068105867899547e-04,    1.622261511817678e-02,
        2.014700000000000e+03,    6.195786864931847e-01,    3.278194108429548e+01,    3.067854428272479e-04,    1.043956653672856e-02,
        2.514700000000000e+03,    7.727975270479135e-01,    3.715372726191892e+01,    3.064376811094576e-04,    8.743572355246868e-03,
        3.014700000000000e+03,    9.259259259259259e-01,    4.061078622482131e+01,    3.062567977560249e-04,    6.914117925804789e-03,
        4.014699999999999e+03,    1.233045622688040e+00,    4.600916502567312e+01,    3.071196967621139e-04,    5.398378800851812e-03,
        5.014700000000000e+03,    1.540832049306626e+00,    4.986511486429210e+01,    3.077864266185862e-04,    3.855949838618981e-03,
        9.014699999999999e+03,    2.590673575129534e+00,    5.512071436445817e+01,    2.624603814557271e-04,    1.313899875041518e-03,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,

        // ===========================================================================================================================

        // Table 2 (14 pressure nodes)
        4.000000000000000e+02,    1.694915254237289e-01,    1.303780964797914e+01,    2.000000000000000e+20,    2.000000000000000e+20,
        8.000000000000000e+02,    3.389830508474577e-01,    2.510985561833020e+01,    4.237288135593221e-04,    3.018011492587764e-02,
        1.200000000000000e+03,    5.102040816326532e-01,    3.644314868804666e+01,    4.280525769629887e-04,    2.833323267429114e-02,
        1.600000000000000e+03,    6.802721088435375e-01,    4.691531785127844e+01,    4.251700680272108e-04,    2.618042290807946e-02,
        2.000000000000000e+03,    8.474576271186441e-01,    5.649717514124294e+01,    4.179637956877669e-04,    2.395464322491127e-02,
        2.400000000000000e+03,    1.020408163265306e+00,    6.583278472679396e+01,    4.323763403666553e-04,    2.333902396387753e-02,
        2.800000000000000e+03,    1.190476190476191e+00,    7.440476190476191e+01,    4.251700680272113e-04,    2.142994294491990e-02,
        3.200000000000000e+03,    1.351351351351352e+00,    8.190008190008190e+01,    4.021879021879017e-04,    1.873829998829995e-02,
        3.600000000000000e+03,    1.538461538461539e+00,    9.049773755656106e+01,    4.677754677754675e-04,    2.149413914119791e-02,
        4.000000000000000e+03,    1.694915254237288e+00,    9.685230024213075e+01,    3.911342894393748e-04,    1.588640671392424e-02,
        4.400000000000000e+03,    1.851851851851852e+00,    1.028806584362140e+02,    3.923414940364085e-04,    1.507089548520804e-02,
        4.800000000000000e+03,    2.040816326530613e+00,    1.103143960286818e+02,    4.724111866969022e-04,    1.858434398116948e-02,
        5.199999999999999e+03,    2.222222222222222e+00,    1.169590643274854e+02,    4.535147392290250e-04,    1.661167074700910e-02,
        5.599999999999999e+03,    2.380952380952381e+00,    1.221001221001221e+02,    3.968253968253976e-04,    1.285264443159182e-02,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
    });

    check_is_close(pvdg, expect_pvdg);
}

BOOST_AUTO_TEST_CASE (PVDG_Exceed_Tabdims_Limits)
{
    // This checks that Flow's extended table allocation scheme does what
    // it's supposed to do.  Normally, one would announce the maximum sizes
    // in the RUNSPEC keyword 'TABDIMS'.  Note that the maximum sizes need
    // to be big enough in order to run the case in ECLIPSE.  Other than
    // NTPVT, Flow does not really care about these declared maximum sizes.

    const auto rspec = std::string { R"(RUNSPEC
DIMENS
  10 10 10 /

TITLE
  Test PVDG Output

GAS

FIELD

TABDIMS
-- NTSFUN  NTPVT  NSSFUN  NPPVT  NTFIP  NRPVT
   1*      2      1*      2      1*     1*
/
)"  };

    const auto props = std::string { R"(
PVDG
  14.7  166.666  0.0080
 264.7   12.093  0.0096
 514.7    6.274  0.0112
1014.7    3.197  0.0140
2014.7    1.614  0.0189
2514.7    1.294  0.0208
3014.7    1.080  0.0228
4014.7    0.811  0.0268
5014.7    0.649  0.0309
9014.7    0.386  0.0470 /
 400.0    5.900  0.0130
 800.0    2.950  0.0135
1200.0    1.960  0.0140
1600.0    1.470  0.0145
2000.0    1.180  0.0150
2400.0    0.980  0.0155
2800.0    0.840  0.0160
3200.0    0.740  0.0165
3600.0    0.650  0.0170
4000.0    0.590  0.0175
4400.0    0.540  0.0180
4800.0    0.490  0.0185
5200.0    0.450  0.0190
5600.0    0.420  0.0195 /
)"  };

    const auto es = parse(rspec, props);

    auto tables = ::Opm::Tables(es.getUnits());
    tables.addPVTTables(es);

    const auto& tabdims = tables.tabdims();
    const auto& tab     = tables.tab();

    const auto ibpvtg = tabdims[ Ix::PvtgMainStart ] - 1;
    const auto nppvtg = tabdims[ Ix::NumPvtgPressNodes ];
    const auto ntpvtg = tabdims[ Ix::NumPvtgTables ];
    const auto ncol   = 5;

    // Pg table defaulted
    BOOST_CHECK_EQUAL(tabdims[Ix::PvtgPressStart], 1);
    BOOST_CHECK_EQUAL(tabdims[Ix::NumPvtgCompNodes], 1);

    BOOST_CHECK_EQUAL(nppvtg, 14); // Table 2
    BOOST_CHECK_EQUAL(ntpvtg,  2);

    const auto pvdg = std::vector<double> {
        &tab[ ibpvtg ] + 0,
        &tab[ ibpvtg ] + ntpvtg*nppvtg*ncol
    };

    const auto expect_pvdg = makeTable(5, {
        // Pg                     1/Bg                      1/(Bg*mu_g)               d(1/Bg)/dPg               d(1/(Bg*mu_g))/dPg
        //
        // Table 1 (10 pressure nodes)
        1.470000000000000e+01,    6.000024000096002e-03,    7.500030000120003e-01,    2.000000000000000e+20,    2.000000000000000e+20,
        2.647000000000000e+02,    8.269246671628215e-02,    8.613798616279391e+00,    3.067697708647446e-04,    3.145518246506956e-02,
        5.147000000000000e+02,    1.593879502709595e-01,    1.423106698847853e+01,    3.067819342187094e-04,    2.246907348879655e-02,
        1.014700000000000e+03,    3.127932436659369e-01,    2.234237454756692e+01,    3.068105867899547e-04,    1.622261511817678e-02,
        2.014700000000000e+03,    6.195786864931847e-01,    3.278194108429548e+01,    3.067854428272479e-04,    1.043956653672856e-02,
        2.514700000000000e+03,    7.727975270479135e-01,    3.715372726191892e+01,    3.064376811094576e-04,    8.743572355246868e-03,
        3.014700000000000e+03,    9.259259259259259e-01,    4.061078622482131e+01,    3.062567977560249e-04,    6.914117925804789e-03,
        4.014699999999999e+03,    1.233045622688040e+00,    4.600916502567312e+01,    3.071196967621139e-04,    5.398378800851812e-03,
        5.014700000000000e+03,    1.540832049306626e+00,    4.986511486429210e+01,    3.077864266185862e-04,    3.855949838618981e-03,
        9.014699999999999e+03,    2.590673575129534e+00,    5.512071436445817e+01,    2.624603814557271e-04,    1.313899875041518e-03,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,

        // ===========================================================================================================================

        // Table 2 (14 pressure nodes)
        4.000000000000000e+02,    1.694915254237289e-01,    1.303780964797914e+01,    2.000000000000000e+20,    2.000000000000000e+20,
        8.000000000000000e+02,    3.389830508474577e-01,    2.510985561833020e+01,    4.237288135593221e-04,    3.018011492587764e-02,
        1.200000000000000e+03,    5.102040816326532e-01,    3.644314868804666e+01,    4.280525769629887e-04,    2.833323267429114e-02,
        1.600000000000000e+03,    6.802721088435375e-01,    4.691531785127844e+01,    4.251700680272108e-04,    2.618042290807946e-02,
        2.000000000000000e+03,    8.474576271186441e-01,    5.649717514124294e+01,    4.179637956877669e-04,    2.395464322491127e-02,
        2.400000000000000e+03,    1.020408163265306e+00,    6.583278472679396e+01,    4.323763403666553e-04,    2.333902396387753e-02,
        2.800000000000000e+03,    1.190476190476191e+00,    7.440476190476191e+01,    4.251700680272113e-04,    2.142994294491990e-02,
        3.200000000000000e+03,    1.351351351351352e+00,    8.190008190008190e+01,    4.021879021879017e-04,    1.873829998829995e-02,
        3.600000000000000e+03,    1.538461538461539e+00,    9.049773755656106e+01,    4.677754677754675e-04,    2.149413914119791e-02,
        4.000000000000000e+03,    1.694915254237288e+00,    9.685230024213075e+01,    3.911342894393748e-04,    1.588640671392424e-02,
        4.400000000000000e+03,    1.851851851851852e+00,    1.028806584362140e+02,    3.923414940364085e-04,    1.507089548520804e-02,
        4.800000000000000e+03,    2.040816326530613e+00,    1.103143960286818e+02,    4.724111866969022e-04,    1.858434398116948e-02,
        5.199999999999999e+03,    2.222222222222222e+00,    1.169590643274854e+02,    4.535147392290250e-04,    1.661167074700910e-02,
        5.599999999999999e+03,    2.380952380952381e+00,    1.221001221001221e+02,    3.968253968253976e-04,    1.285264443159182e-02,
    });

    check_is_close(pvdg, expect_pvdg);
}

BOOST_AUTO_TEST_CASE (PVTG_USat_Defaulted)
{
    const auto rspec = std::string { R"(RUNSPEC
DIMENS
  10 10 10 /

TITLE
  Test PVTG Output

GAS

METRIC

TABDIMS
-- NTSFUN  NTPVT  NSSFUN  NPPVT  NTFIP  NRPVT
   1*      2      1*      7      1*     2
/
)"  };

    const auto props = std::string { R"(
PVTG
30  0.00014 0.0523  0.0234
    0       0.0521  0.0238 /
90  0.00012 0.0132  0.0252
    0       0.0131  0.0253 /
150 0.00015 0.00877 0.0281
    0       0.00861 0.0275 /
210 0.00019 0.00554 0.0318
    0       0.00555 0.0302 /
270 0.00029 0.00417 0.0355
    0       0.00421 0.0330 /
330 0.00049 0.00357 0.0392
    0       0.00361 0.0358 /
530 0.00060 0.00356 0.0393
    0       0.00360 0.0359 /
/
60  0.00014 0.0523  0.0234 /
120 0.00012 0.0132  0.0252 /
180 0.00015 0.00877 0.0281 /
240 0.00019 0.00554 0.0318 /
300 0.00029 0.00417 0.0355 /
360 0.00049 0.00357 0.0392 /
560 0.00060 0.00356 0.0393
    0       0.00360 0.0359 /
/
)"  };

    const auto es = parse(rspec, props);

    auto tables = ::Opm::Tables(es.getUnits());
    tables.addPVTTables(es);

    const auto& tabdims = tables.tabdims();
    const auto& tab     = tables.tab();

    const auto ibpvtg = tabdims[ Ix::PvtgMainStart ] - 1;
    const auto jbpvtg = tabdims[ Ix::PvtgPressStart ] - 1;
    const auto nppvtg = tabdims[ Ix::NumPvtgPressNodes ];
    const auto nrpvtg = tabdims[ Ix::NumPvtgCompNodes ];
    const auto ntpvtg = tabdims[ Ix::NumPvtgTables ];
    const auto ncol   = 5;

    BOOST_CHECK_EQUAL(nppvtg, 7 + 2); // 7 regular + 2 padding nodes.
    BOOST_CHECK_EQUAL(nrpvtg, 2);
    BOOST_CHECK_EQUAL(ntpvtg, 2);

    const auto pvtg = std::vector<double> {
        &tab[ ibpvtg ] + 0,
        &tab[ ibpvtg ] + ntpvtg*nppvtg*nrpvtg*ncol
    };

    const auto pg = std::vector<double> {
        &tab[ jbpvtg ] + 0,
        &tab[ jbpvtg ] + ntpvtg*nppvtg
    };

    const auto expect_pvtg = makeTable(5, {
        // Rv                     1/Bg                      1/(Bg*mu_g)               d(1/Bg)/dRv               d(1/(Bg*mu_g))/dRv
        //
        // Table 1 (Pg 1, 1 barsa, padding value)
        1.463987928388746e-04,    0.90909090909090906  ,    1.061101444733158e+02,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,

        // Table 1 (Pg 2, pLim, padding value) ---------------------------------------------------------------------------------------

        1.463987928388746e-04,    1.0                  ,    1.167211589206474e+02,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,

        // Table 1 (Pg 3) ------------------------------------------------------------------------------------------------------------

        1.400000000000000e-04,    1.912045889101339e+01,    8.171136278210848e+02,   -2.000000000000000e+20,   -2.000000000000000e+20,
                            0,    1.919385796545106e+01,    8.064646203971031e+02,   -5.242791031262176e+02,    7.606433874272674e+04,

        // Table 1 (Pg 4) ------------------------------------------------------------------------------------------------------------

        1.200000000000000e-04,    7.575757575757576e+01,    3.006253006253006e+03,   -2.000000000000000e+20,   -2.000000000000000e+20,
                            0,    7.633587786259541e+01,    3.017228374015629e+03,   -4.819184208497044e+03,   -9.146139802185188e+04,

        // Table 1 (Pg 5) ------------------------------------------------------------------------------------------------------------

        1.500000000000000e-04,    1.140250855188141e+02,    4.057832224868830e+03,   -2.000000000000000e+20,   -2.000000000000000e+20,
                            0,    1.161440185830430e+02,    4.223418857565199e+03,   -1.412622042819227e+04,   -1.103910884642458e+06,

        // Table 1 (Pg 6) ------------------------------------------------------------------------------------------------------------

        1.900000000000000e-04,    1.805054151624549e+02,    5.676270917058329e+03,   -2.000000000000000e+20,   -2.000000000000000e+20,
                            0,    1.801801801801802e+02,    5.966231131794045e+03,    1.711763064603725e+03,   -1.526106393345871e+06,

        // Table 1 (Pg 7) ------------------------------------------------------------------------------------------------------------

        2.900000000000000e-04,    2.398081534772182e+02,    6.755159252879387e+03,   -2.000000000000000e+20,   -2.000000000000000e+20,
                            0,    2.375296912114014e+02,    7.197869430648528e+03,    7.856766433850982e+03,   -1.526586819893588e+06,

        // Table 1 (Pg 8) ------------------------------------------------------------------------------------------------------------

        4.900000000000000e-04,    2.801120448179272e+02,    7.145715429028755e+03,   -2.000000000000000e+20,   -2.000000000000000e+20,
                            0,    2.770083102493075e+02,    7.737662297466691e+03,    6.334152180856531e+03,   -1.208054833546807e+06,

        // Table 1 (Pg 9) ------------------------------------------------------------------------------------------------------------

        5.999999999999999e-04,    2.808988764044944e+02,    7.147554106984589e+03,   -2.000000000000000e+20,   -2.000000000000000e+20,
                            0,    2.777777777777778e+02,    7.737542556484059e+03,    5.201831044527695e+03,   -9.833140824991158e+05,

        // ==========================================================================================================================

        // Table 2 (Pg 1, 1 barsa, padding value)
        1.463987928388746e-04,    0.90909090909090906  ,    1.061101444733159e+02,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,

        // Table 2 (Pg 2, pLim, padding value) ---------------------------------------------------------------------------------------

        1.463987928388746e-04,    1.0                  ,    1.167211589206474e+02,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,

        // Table 2 (Pg 3) ------------------------------------------------------------------------------------------------------------

        1.400000000000000e-04,    1.912045889101339e+01,    8.171136278210848e+02,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,

        // Table 2 (Pg 4) ------------------------------------------------------------------------------------------------------------

        1.200000000000000e-04,    7.575757575757576e+01,    3.006253006253006e+03,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,

        // Table 2 (Pg 5) ------------------------------------------------------------------------------------------------------------

        1.500000000000000e-04,    1.140250855188141e+02,    4.057832224868830e+03,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,

        // Table 2 (Pg 6) ------------------------------------------------------------------------------------------------------------

        1.900000000000000e-04,    1.805054151624549e+02,    5.676270917058329e+03,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,

        // Table 2 (Pg 7) ------------------------------------------------------------------------------------------------------------

        2.900000000000000e-04,    2.398081534772182e+02,    6.755159252879387e+03,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,

        // Table 2 (Pg 8) ------------------------------------------------------------------------------------------------------------

        4.900000000000000e-04,    2.801120448179272e+02,    7.145715429028755e+03,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,

        // Table 2 (Pg 9) ------------------------------------------------------------------------------------------------------------

        5.999999999999999e-04,    2.808988764044944e+02,    7.147554106984589e+03,   -2.000000000000000e+20,   -2.000000000000000e+20,
                            0,    2.777777777777778e+02,    7.737542556484059e+03,    5.201831044527695e+03,   -9.833140824991158e+05,
    });

    const auto expect_pg = makeTable(1, {
        // Table 1
        1.0,                    // <-- p=1 bar (padding value)
        10.803621483375961,     // <-- p=pLim (padding value)
        30.0, 90.0, 150.0, 210.0, 270.0, 330.0, 530.0,

        // Table 2
        1.0,                    // <-- p=1 bar (padding value)
        40.803621483375963,     // <-- p=pLim (padding value)
        60.0, 120.0, 180.0, 240.0, 300.0, 360.0, 560.0,
    });

    check_is_close(pvtg, expect_pvtg);
    check_is_close(pg  , expect_pg  );
}

BOOST_AUTO_TEST_CASE (PVTG_USat_Full_Large_Tabdims)
{
    const auto rspec = std::string { R"(RUNSPEC
DIMENS
  10 10 10 /

TITLE
  Test PVTG Output

GAS

METRIC

TABDIMS
-- NTSFUN  NTPVT  NSSFUN  NPPVT  NTFIP  NRPVT
   1*      1      1*      7      1*     5
/
)"  };

    const auto props = std::string { R"(
PVTG
 50.00    0.00000497   0.024958     0.01441
          0.00000248   0.024958     0.01440
          0.00000000   0.024958     0.01440 /
 70.00    0.00000521   0.017639     0.01491
          0.00000261   0.017641     0.01490
          0.00000000   0.017643     0.01490 /
 90.00    0.00000627   0.013608     0.01547
          0.00000313   0.013611     0.01546
          0.00000000   0.013615     0.01544 /
110.00    0.00000798   0.011072     0.01609
          0.00000399   0.011076     0.01607
          0.00000000   0.011081     0.01605 /
/
)"  };

    const auto es = parse(rspec, props);

    auto tables = ::Opm::Tables(es.getUnits());
    tables.addPVTTables(es);

    const auto& tabdims = tables.tabdims();
    const auto& tab     = tables.tab();

    const auto ibpvtg = tabdims[ Ix::PvtgMainStart ] - 1;
    const auto jbpvtg = tabdims[ Ix::PvtgPressStart ] - 1;
    const auto nppvtg = tabdims[ Ix::NumPvtgPressNodes ];
    const auto nrpvtg = tabdims[ Ix::NumPvtgCompNodes ];
    const auto ntpvtg = tabdims[ Ix::NumPvtgTables ];
    const auto ncol   = 5;

    BOOST_CHECK_EQUAL(nppvtg, 7); // From TABDIMS.  Exceeds 4 regular + 2 padding nodes.
    BOOST_CHECK_EQUAL(nrpvtg, 5);
    BOOST_CHECK_EQUAL(ntpvtg, 1);

    const auto pvtg = std::vector<double> {
        &tab[ ibpvtg ] + 0,
        &tab[ ibpvtg ] + ntpvtg*nppvtg*nrpvtg*ncol
    };

    const auto pg = std::vector<double> {
        &tab[ jbpvtg ] + 0,
        &tab[ jbpvtg ] + ntpvtg*nppvtg
    };

    const auto expect_pvtg = makeTable(5, {
        // Rv                     1/Bg                      1/(Bg*mu_g)               d(1/Bg)/dRv               d(1/(Bg*mu_g))/dRv
        //
        // Table 1 (Pg 1, 1 barsa, padding value)

        4.406028992878809e-06,    0.90909090909090906  ,    3.449305141722682e+02,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,

        // Table 1 (Pg 2, pLim, padding value) ---------------------------------------------------------------------------------------

        4.406028992878809e-06,    1.0                  ,    3.794235655894950e+02,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,

        // Table 1 (Pg 3) ------------------------------------------------------------------------------------------------------------

        4.970000000000000e-06,    4.006731308598445e+01,    2.780521380012800e+03,   -2.000000000000000e+20,   -2.000000000000000e+20,
        2.480000000000000e-06,    4.006731308598445e+01,    2.782452297637809e+03,                        0,   -7.754689257064208e+05,
                            0,    4.006731308598445e+01,    2.782452297637809e+03,                        0,                        0,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,

        // Table 1 (Pg 4) ------------------------------------------------------------------------------------------------------------

        5.210000000000000e-06,    5.669255626736210e+01,    3.802317657100074e+03,   -2.000000000000000e+20,   -2.000000000000000e+20,
        2.610000000000000e-06,    5.668612890425712e+01,    3.804438181493767e+03,    2.472062732683009e+03,   -8.155863052665014e+05,
                            0,    5.667970299835629e+01,    3.804006912641362e+03,    2.462032912196776e+03,    1.652371082011811e+05,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,

        // Table 1 (Pg 5) ------------------------------------------------------------------------------------------------------------

        6.270000000000000e-06,    7.348618459729570e+01,    4.750238176942192e+03,   -2.000000000000000e+20,   -2.000000000000000e+20,
        3.130000000000000e-06,    7.346998751010213e+01,    4.752263098971676e+03,    5.158308023431543e+03,   -6.448796272243677e+05,
                            0,    7.344840249724568e+01,    4.757020887127311e+03,    6.896170241676778e+03,   -1.520060113621228e+06,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,

        // Table 1 (Pg 6) ------------------------------------------------------------------------------------------------------------

        7.980000000000000e-06,    9.031791907514450e+01,    5.613295156938751e+03,   -2.000000000000000e+20,   -2.000000000000000e+20,
        3.990000000000000e-06,    9.028530155290719e+01,    5.618251496758381e+03,    8.174817603337499e+03,   -1.242190430985102e+06,
                            0,    9.024456276509339e+01,    5.622714190971551e+03,    1.021022250972279e+04,   -1.118469727611510e+06,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,

        // Table 1 (Pg 7) ------------------------------------------------------------------------------------------------------------

       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,
    });

    const auto expect_pg = makeTable(1, {
        // Table 1
        1.0,                    // <-- p=1 barsa, padding value
        3.002416073234063,      // <-- p=pLim, padding value
        50.00, 70.00, 90.00, 110.00, 2.0e20,
    });

    check_is_close(pvtg, expect_pvtg);
    check_is_close(pg  , expect_pg  );
}

BOOST_AUTO_TEST_CASE (PVTG_Exceed_Tabdims_Limits)
{
    // This checks that Flow's extended table allocation scheme does what
    // it's supposed to do.  Normally, one would announce the maximum sizes
    // in the RUNSPEC keyword 'TABDIMS'.  Note that the maximum sizes need
    // to be big enough in order to run the case in ECLIPSE.  Other than
    // NTPVT, Flow does not really care about these declared maximum sizes.

    const auto rspec = std::string { R"(RUNSPEC
DIMENS
  10 10 10 /

TITLE
  Test PVTG Output

GAS

METRIC

TABDIMS
-- NTSFUN  NTPVT  NSSFUN  NPPVT  NTFIP  NRPVT
   1*      2      1*      1      1*     1
/
)"  };

    const auto props = std::string { R"(
PVTG
 50.00    0.00000497   0.024958     0.01441
          0.00000248   0.024958     0.01440
          0.00000000   0.024958     0.01440 /
 70.00    0.00000521   0.017639     0.01491
          0.00000261   0.017641     0.01490
          0.00000000   0.017643     0.01490 /
 90.00    0.00000627   0.013608     0.01547
          0.00000313   0.013611     0.01546
          0.00000000   0.013615     0.01544 /
110.00    0.00000798   0.011072     0.01609
          0.00000399   0.011076     0.01607
          0.00000000   0.011081     0.01605 /
130.00    0.00001041   0.009340     0.01677
          0.00000520   0.009346     0.01674
          0.00000000   0.009352     0.01671 /
/
 50.00    0.00000497   0.024958     0.01441
          0.00000248   0.024958     0.01440
          0.00000000   0.024958     0.01440 /
/
)"  };

    const auto es = parse(rspec, props);

    auto tables = ::Opm::Tables(es.getUnits());
    tables.addPVTTables(es);

    const auto& tabdims = tables.tabdims();
    const auto& tab     = tables.tab();

    const auto ibpvtg = tabdims[ Ix::PvtgMainStart ] - 1;
    const auto jbpvtg = tabdims[ Ix::PvtgPressStart ] - 1;
    const auto nppvtg = tabdims[ Ix::NumPvtgPressNodes ];
    const auto nrpvtg = tabdims[ Ix::NumPvtgCompNodes ];
    const auto ntpvtg = tabdims[ Ix::NumPvtgTables ];
    const auto ncol   = 5;

    BOOST_CHECK_EQUAL(nppvtg, 5 + 2); // Table 1, 5 regular + 2 padding nodes.
    BOOST_CHECK_EQUAL(nrpvtg, 3); // Table 1, Pg 1
    BOOST_CHECK_EQUAL(ntpvtg, 2); // TABDIMS

    const auto pvtg = std::vector<double> {
        &tab[ ibpvtg ] + 0,
        &tab[ ibpvtg ] + ntpvtg*nppvtg*nrpvtg*ncol
    };

    const auto pg = std::vector<double> {
        &tab[ jbpvtg ] + 0,
        &tab[ jbpvtg ] + ntpvtg*nppvtg
    };

    const auto expect_pvtg = makeTable(5, {
        // Rv                     1/Bg                      1/(Bg*mu_g)               d(1/Bg)/dRv               d(1/(Bg*mu_g))/dRv
        //
        // Table 1 (Pg 1, p=1 barsa, padding value)

        4.406028992878809e-06,    0.90909090909090906  ,    3.449305141722682e+02,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,

        // Table 1 (Pg 2, p=pLim, padding value) -------------------------------------------------------------------------------------

        4.406028992878809e-06,    1.0                  ,    3.794235655894950e+02,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,

        // Table 1 (Pg 3) ------------------------------------------------------------------------------------------------------------

        4.970000000000000e-06,    4.006731308598445e+01,    2.780521380012800e+03,   -2.000000000000000e+20,   -2.000000000000000e+20,
        2.480000000000000e-06,    4.006731308598445e+01,    2.782452297637809e+03,                        0,   -7.754689257064208e+05,
                            0,    4.006731308598445e+01,    2.782452297637809e+03,                        0,                        0,

        // Table 1 (Pg 4) ------------------------------------------------------------------------------------------------------------

        5.210000000000000e-06,    5.669255626736210e+01,    3.802317657100074e+03,   -2.000000000000000e+20,   -2.000000000000000e+20,
        2.610000000000000e-06,    5.668612890425712e+01,    3.804438181493767e+03,    2.472062732683009e+03,   -8.155863052665014e+05,
                            0,    5.667970299835629e+01,    3.804006912641362e+03,    2.462032912196776e+03,    1.652371082011811e+05,

        // Table 1 (Pg 5) ------------------------------------------------------------------------------------------------------------

        6.270000000000000e-06,    7.348618459729570e+01,    4.750238176942192e+03,   -2.000000000000000e+20,   -2.000000000000000e+20,
        3.130000000000000e-06,    7.346998751010213e+01,    4.752263098971676e+03,    5.158308023431543e+03,   -6.448796272243677e+05,
                            0,    7.344840249724568e+01,    4.757020887127311e+03,    6.896170241676778e+03,   -1.520060113621228e+06,

        // Table 1 (Pg 6) ------------------------------------------------------------------------------------------------------------

        7.980000000000000e-06,    9.031791907514450e+01,    5.613295156938751e+03,   -2.000000000000000e+20,   -2.000000000000000e+20,
        3.990000000000000e-06,    9.028530155290719e+01,    5.618251496758381e+03,    8.174817603337499e+03,   -1.242190430985102e+06,
                            0,    9.024456276509339e+01,    5.622714190971551e+03,    1.021022250972279e+04,   -1.118469727611510e+06,

        // Table 1 (Pg 7) ------------------------------------------------------------------------------------------------------------

        1.041000000000000e-05,    1.070663811563169e+02,    6.384399591909179e+03,   -2.000000000000000e+20,   -2.000000000000000e+20,
        5.200000000000000e-06,    1.069976460517869e+02,    6.391735128541628e+03,    1.319291833590461e+04,   -1.407972482235984e+06,
                            0,    1.069289991445680e+02,    6.399102282738958e+03,    1.320132831131706e+04,   -1.416760422563444e+06,

        // ==========================================================================================================================

        // Table 2 (Pg 1)
        4.970000000000000e-06,    4.006731308598445e+01,    2.780521380012800e+03,   -2.000000000000000e+20,   -2.000000000000000e+20,
        2.480000000000000e-06,    4.006731308598445e+01,    2.782452297637809e+03,                        0,   -7.754689257064208e+05,
                            0,    4.006731308598445e+01,    2.782452297637809e+03,                        0,                        0,

        // Table 2 (Pg 2) ------------------------------------------------------------------------------------------------------------

       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,

        // Table 2 (Pg 3) ------------------------------------------------------------------------------------------------------------

       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,

        // Table 2 (Pg 4) ------------------------------------------------------------------------------------------------------------

       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,

        // Table 2 (Pg 5) ------------------------------------------------------------------------------------------------------------

       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,

        // Table 2 (Pg 6) ------------------------------------------------------------------------------------------------------------

       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,

        // Table 2 (Pg 7) ------------------------------------------------------------------------------------------------------------

       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,
       -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,   -2.000000000000000e+20,
    });

    const auto expect_pg = makeTable(1, {
        // Table 1
        1.0,                    // p=1 barsa, padding value
        3.002416073234063,      // p=pLim, padding value
        50.00, 70.00, 90.00, 110.00, 130.0,

        // Table 2
        50.00, 2.0e20, 2.0e20, 2.0e20, 2.0e20, 2.0e20, 2.0e20,
    });

    check_is_close(pvtg, expect_pvtg);
    check_is_close(pg  , expect_pg  );
}

BOOST_AUTO_TEST_SUITE_END ()

// =====================================================================

BOOST_AUTO_TEST_SUITE (Oil)

BOOST_AUTO_TEST_CASE (PVCDO)
{
    const auto rspec = std::string { R"(RUNSPEC
DIMENS
  10 10 10 /

TITLE
  Test PVCDO Output

OIL
WATER

METRIC

TABDIMS
-- NTSFUN  NTPVT  NSSFUN  NPPVT  NTFIP  NRPVT
   1*      2      1*      4      1*     3
/
)"  };

    const auto props = std::string { R"(
PVCDO
-- Pref  Bo(Pref)  Co        Vo(Pref)  Cv
   200   1.23      0.321e-4  0.25      0.654e-3 /
   250   0.987     1.234e-5  0.314     0.9876e-5 /
)"  };

    const auto es = parse(rspec, props);

    auto tables = ::Opm::Tables(es.getUnits());
    tables.addPVTTables(es);

    const auto& tabdims = tables.tabdims();
    const auto& tab     = tables.tab();

    const auto ibpvto = tabdims[ Ix::PvtoMainStart ] - 1;
    const auto nppvto = tabdims[ Ix::NumPvtoPressNodes ];
    const auto ntpvto = tabdims[ Ix::NumPvtoTables ];
    const auto ncol   = 5;

    // Rs table defaulted
    BOOST_CHECK_EQUAL(tabdims[Ix::PvtoCompStart], 1);
    BOOST_CHECK_EQUAL(tabdims[Ix::NumPvtoCompNodes], 1);

    BOOST_CHECK_EQUAL(nppvto, 4);
    BOOST_CHECK_EQUAL(ntpvto, 2);

    const auto pvcdo = std::vector<double> {
        &tab[ ibpvto ] + 0,
        &tab[ ibpvto ] + ntpvto*nppvto*ncol
    };

    const auto expect_pvcdo = makeTable(5, {
         // Po                     Bo                        Co                        Vo                        Cv
         //
         // Table 1
         2.000000000000000e+02,    1.230000000000000e+00,    3.210000000000000e-05,    2.500000000000000e-01,    6.540000000000001e-04,
        -1.000000000000000e+20,   -1.000000000000000e+20,   -1.000000000000000e+20,   -1.000000000000000e+20,   -1.000000000000000e+20,
        -1.000000000000000e+20,   -1.000000000000000e+20,   -1.000000000000000e+20,   -1.000000000000000e+20,   -1.000000000000000e+20,
        -1.000000000000000e+20,   -1.000000000000000e+20,   -1.000000000000000e+20,   -1.000000000000000e+20,   -1.000000000000000e+20,

        // ===========================================================================================================================

        // Table 2
         2.500000000000000e+02,    9.870000000000000e-01,    1.234000000000000e-05,    3.140000000000000e-01,    9.876000000000000e-06,
        -1.000000000000000e+20,   -1.000000000000000e+20,   -1.000000000000000e+20,   -1.000000000000000e+20,   -1.000000000000000e+20,
        -1.000000000000000e+20,   -1.000000000000000e+20,   -1.000000000000000e+20,   -1.000000000000000e+20,   -1.000000000000000e+20,
        -1.000000000000000e+20,   -1.000000000000000e+20,   -1.000000000000000e+20,   -1.000000000000000e+20,   -1.000000000000000e+20,
    });

    check_is_close(pvcdo, expect_pvcdo);
}

BOOST_AUTO_TEST_CASE (PVDO_Regular)
{
    const auto rspec = std::string { R"(RUNSPEC
DIMENS
  10 10 10 /

TITLE
  Test PVDO Output

OIL
WATER

FIELD

TABDIMS
-- NTSFUN  NTPVT  NSSFUN  NPPVT  NTFIP  NRPVT
   1*      2      1*      8      1*     1*
/
)"  };

    const auto props = std::string { R"(
PVDO
400  1.012  1.16
1200 1.0040 1.164
2000 0.9960 1.167
2800 0.9880 1.172
3600 0.9802 1.177
4400 0.9724 1.181
5200 0.9646 1.185
5600 0.9607 1.19 /
800  1.0255 1.14
1600 1.0172 1.14
2400 1.0091 1.14
3200 1.0011 1.14
4000 0.9931 1.14
4800 0.9852 1.14
5600 0.9774 1.14 /
)"  };

    const auto es = parse(rspec, props);

    auto tables = ::Opm::Tables(es.getUnits());
    tables.addPVTTables(es);

    const auto& tabdims = tables.tabdims();
    const auto& tab     = tables.tab();

    const auto ibpvto = tabdims[ Ix::PvtoMainStart ] - 1;
    const auto nppvto = tabdims[ Ix::NumPvtoPressNodes ];
    const auto ntpvto = tabdims[ Ix::NumPvtoTables ];
    const auto ncol   = 5;

    // Rs table defaulted
    BOOST_CHECK_EQUAL(tabdims[Ix::PvtoCompStart], 1);
    BOOST_CHECK_EQUAL(tabdims[Ix::NumPvtoCompNodes], 1);

    BOOST_CHECK_EQUAL(nppvto, 8);
    BOOST_CHECK_EQUAL(ntpvto, 2);

    const auto pvdo = std::vector<double> {
        &tab[ ibpvto ] + 0,
        &tab[ ibpvto ] + ntpvto*nppvto*ncol
    };

    const auto expect_pvdo = makeTable(5, {
        // Po                     1/Bo                      1/(Bo*mu_o)               d(1/Bo)/dPo               d(1/(Bo*mu_o))/dPo
        //
        // Table 1 (8 pressure nodes)
        4.000000000000000e+02,    9.881422924901185e-01,    8.518468038707919e-01,    2.000000000000000e+20,    2.000000000000000e+20,
        1.200000000000000e+03,    9.960159362549801e-01,    8.556837940334882e-01,    9.842054706076935e-06,    4.796237703370287e-06,
        2.000000000000000e+03,    1.004016064257028e+00,    8.603393866812581e-01,    1.000016000256010e-05,    5.819490809712421e-06,
        2.800000000000000e+03,    1.012145748987854e+00,    8.636055878735959e-01,    1.016210591353262e-05,    4.082751490422227e-06,
        3.600000000000000e+03,    1.020199959192002e+00,    8.667799143517431e-01,    1.006776275518428e-05,    3.967908097683990e-06,
        4.400000000000000e+03,    1.028383381324558e+00,    8.707733965491598e-01,    1.022927766569509e-05,    4.991852746770858e-06,
        5.199999999999999e+03,    1.036699149906697e+00,    8.748516032967908e-01,    1.039471072767418e-05,    5.097758434538807e-06,
        5.599999999999999e+03,    1.040907671489539e+00,    8.747123289828058e-01,    1.052130395710449e-05,   -3.481857849624292e-07,

        // ===========================================================================================================================

        // Table 2 (7 pressure nodes)
        8.000000000000000e+02,    9.751340809361286e-01,    8.553807727509901e-01,    2.000000000000000e+20,    2.000000000000000e+20,
        1.600000000000000e+03,    9.830908375933936e-01,    8.623603838538541e-01,    9.945945821581148e-06,    8.724513878579920e-06,
        2.400000000000000e+03,    9.909820632246555e-01,    8.692825116005751e-01,    9.864032039077486e-06,    8.652659683401343e-06,
        3.200000000000000e+03,    9.989012086704624e-01,    8.762291304126864e-01,    9.898931807258565e-06,    8.683273515139035e-06,
        4.000000000000000e+03,    1.006947940791461e+00,    8.832876673609308e-01,    1.005841515124826e-05,    8.823171185305545e-06,
        4.800000000000000e+03,    1.015022330491271e+00,    8.903704653432202e-01,    1.009298712476236e-05,    8.853497477861732e-06,
        5.599999999999999e+03,    1.023122570083896e+00,    8.974759386700842e-01,    1.012529949078135e-05,    8.881841658580091e-06,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
    });

    check_is_close(pvdo, expect_pvdo);
}

BOOST_AUTO_TEST_CASE (PVDO_Exceed_Tabdims_Limits)
{
    // This checks that Flow's extended table allocation scheme does what
    // it's supposed to do.  Normally, one would announce the maximum sizes
    // in the RUNSPEC keyword 'TABDIMS'.  Note that the maximum sizes need
    // to be big enough in order to run the case in ECLIPSE.  Other than
    // NTPVT, Flow does not really care about these declared maximum sizes.

    const auto rspec = std::string { R"(RUNSPEC
DIMENS
  10 10 10 /

TITLE
  Test PVDO Output

OIL
WATER

FIELD

TABDIMS
-- NTSFUN  NTPVT  NSSFUN  NPPVT  NTFIP  NRPVT
   1*      2      1*      2      1*     1*
/
)"  };

    const auto props = std::string { R"(
PVDO
400  1.012  1.16
1200 1.0040 1.164
2000 0.9960 1.167
2800 0.9880 1.172
3600 0.9802 1.177
4000 0.9752 1.179
4400 0.9724 1.181
5200 0.9646 1.185
5400 0.9630 1.187
5600 0.9607 1.19 /
800  1.0255 1.14
1600 1.0172 1.14
5600 0.9774 1.14 /
)"  };

    const auto es = parse(rspec, props);

    auto tables = ::Opm::Tables(es.getUnits());
    tables.addPVTTables(es);

    const auto& tabdims = tables.tabdims();
    const auto& tab     = tables.tab();

    const auto ibpvto = tabdims[ Ix::PvtoMainStart ] - 1;
    const auto nppvto = tabdims[ Ix::NumPvtoPressNodes ];
    const auto ntpvto = tabdims[ Ix::NumPvtoTables ];
    const auto ncol   = 5;

    // Rs table defaulted
    BOOST_CHECK_EQUAL(tabdims[Ix::PvtoCompStart], 1);
    BOOST_CHECK_EQUAL(tabdims[Ix::NumPvtoCompNodes], 1);

    BOOST_CHECK_EQUAL(nppvto, 10); // Table 1
    BOOST_CHECK_EQUAL(ntpvto,  2);

    // Verify declared TABDIMS from input
    {
        const auto& tabd = es.runspec().tabdims();

        BOOST_CHECK_EQUAL(tabd.getNumPVTTables(),     2U);
        BOOST_CHECK_EQUAL(tabd.getNumPressureNodes(), 2U);
    }

    const auto pvdo = std::vector<double> {
        &tab[ ibpvto ] + 0,
        &tab[ ibpvto ] + ntpvto*nppvto*ncol
    };

    const auto expect_pvdo = makeTable(5, {
        // Po                     1/Bo                      1/(Bo*mu_o)               d(1/Bo)/dPo               d(1/(Bo*mu_o))/dPo
        //
        // Table 1 (10 pressure nodes)
        4.000000000000000e+02,    9.881422924901185e-01,    8.518468038707919e-01,    2.000000000000000e+20,    2.000000000000000e+20,
        1.200000000000000e+03,    9.960159362549801e-01,    8.556837940334882e-01,    9.842054706076935e-06,    4.796237703370287e-06,
        2.000000000000000e+03,    1.004016064257028e+00,    8.603393866812581e-01,    1.000016000256010e-05,    5.819490809712421e-06,
        2.800000000000000e+03,    1.012145748987854e+00,    8.636055878735959e-01,    1.016210591353262e-05,    4.082751490422227e-06,
        3.600000000000000e+03,    1.020199959192002e+00,    8.667799143517431e-01,    1.006776275518428e-05,    3.967908097683990e-06,
        4.000000000000000e+03,    1.025430680885972e+00,    8.697461245852181e-01,    1.307680423492609e-05,    7.415525583687474e-06,
        4.400000000000000e+03,    1.028383381324558e+00,    8.707733965491598e-01,    7.381751096464098e-06,    2.568179909854249e-06,
        5.199999999999999e+03,    1.036699149906697e+00,    8.748516032967908e-01,    1.039471072767418e-05,    5.097758434538807e-06,
        5.400000000000000e+03,    1.038421599169263e+00,    8.748286429395642e-01,    8.612246312827937e-06,   -1.148017861329892e-07,
        5.599999999999999e+03,    1.040907671489539e+00,    8.747123289828058e-01,    1.243036160138106e-05,   -5.815697837918713e-07,

        // ===========================================================================================================================

        // Table 2 (3 pressure nodes)
        8.000000000000000e+02,    9.751340809361286e-01,    8.553807727509901e-01,    2.000000000000000e+20,    2.000000000000000e+20,
        1.600000000000000e+03,    9.830908375933936e-01,    8.623603838538541e-01,    9.945945821581148e-06,    8.724513878579920e-06,
        5.599999999999999e+03,    1.023122570083896e+00,    8.974759386700842e-01,    1.000793312262560e-05,    8.778888704057549e-06,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
    });

    check_is_close(pvdo, expect_pvdo);
}

BOOST_AUTO_TEST_CASE (PVTO_SPE1_USat_Defaulted)
{
    const auto rspec = std::string { R"(RUNSPEC
DIMENS
  10 10 10 /

TITLE
  Test PVTO Output

OIL
WATER

FIELD

TABDIMS
-- NTSFUN  NTPVT  NSSFUN  NPPVT  NTFIP  NRPVT
   1*      2      1*      4      1*     3
/
)"  };

    const auto props = std::string { R"(
PVTO
0.3710  1014.7  1.2950  0.8300 /
0.9300  3014.7  1.5650  0.5940 /
1.6180  5014.7  1.8270  0.4490
        9014.7  1.7370  0.6310 /
/
0.0010  14.7    1.0620  1.0400 /
1.2700  4014.7  1.6950  0.5100
        9014.7  1.5790  0.7400 /
/
)"  };

    const auto es = parse(rspec, props);

    auto tables = ::Opm::Tables(es.getUnits());
    tables.addPVTTables(es);

    const auto& tabdims = tables.tabdims();
    const auto& tab     = tables.tab();

    const auto ibpvto = tabdims[ Ix::PvtoMainStart ] - 1;
    const auto jbpvto = tabdims[ Ix::PvtoCompStart ] - 1;
    const auto nppvto = tabdims[ Ix::NumPvtoPressNodes ];
    const auto nrpvto = tabdims[ Ix::NumPvtoCompNodes ];
    const auto ntpvto = tabdims[ Ix::NumPvtoTables ];
    const auto ncol   = 5;

    BOOST_CHECK_EQUAL(nppvto, 4);
    BOOST_CHECK_EQUAL(nrpvto, 3);
    BOOST_CHECK_EQUAL(ntpvto, 2);

    const auto pvto = std::vector<double> {
        &tab[ ibpvto ] + 0,
        &tab[ ibpvto ] + ntpvto*nrpvto*nppvto*ncol
    };

    const auto rs = std::vector<double> {
        &tab[ jbpvto ] + 0,
        &tab[ jbpvto ] + ntpvto*nrpvto
    };

    const auto expect_pvto = makeTable(5, {
        // Po                     1/Bo                      1/(Bo*mu_o)               d(1/Bo)/dPo               d(1/(Bo*mu_o))/dPo
        //
        // Table 1 (Comp 1)
        1.014700000000000e+03,    7.722007722007722e-01,    9.303623761455088e-01,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,

        // Table 1 (Comp 2) ----------------------------------------------------------------------------------------------------------

        3.014700000000000e+03,    6.389776357827476e-01,    1.075719925560181e+00,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,

        // Table 1 (Comp 3) ----------------------------------------------------------------------------------------------------------

        5.014700000000000e+03,    5.473453749315819e-01,    1.219032015437822e+00,    2.000000000000000e+20,    2.000000000000000e+20,
        9.014699999999999e+03,    5.757052389176741e-01,    9.123696337839526e-01,    7.089965996523064e-06,   -7.666559541346725e-05,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,

        // ==========================================================================================================================

        // Table 2 (Comp 1)
        1.470000000000000e+01,    9.416195856873822e-01,    9.054034477763291e-01,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,

        // Table 2 (Comp 2) ----------------------------------------------------------------------------------------------------------

        4.014699999999999e+03,    5.899705014749262e-01,    1.156804904852797e+00,    2.000000000000000e+20,    2.000000000000000e+20,
        9.014699999999999e+03,    6.333122229259025e-01,    8.558273282782466e-01,    8.668344290195251e-06,   -6.019551531491001e-05,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,

        // Table 2 (Comp 3, unused) --------------------------------------------------------------------------------------------------

        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
    });

    const auto expect_rs = makeTable(1, {
        // Table 1
        0.3710, 0.9300, 1.6180,

        // Table 2
        0.0010, 1.2700, 2.0e+20,
    });

    check_is_close(pvto, expect_pvto);
    check_is_close(rs  , expect_rs  );
}

BOOST_AUTO_TEST_CASE (PVTO_USat_Full)
{
    const auto rspec = std::string { R"(RUNSPEC
DIMENS
  10 10 10 /

TITLE
  Test PVTO Output

OIL
WATER

METRIC

TABDIMS
-- NTSFUN  NTPVT  NSSFUN  NPPVT  NTFIP  NRPVT
   1*      2      1*      5      1*     4
/
)"  };

    const auto props = std::string { R"(
PVTO
20.59  50.00 1.10615 1.180
       75.00 1.10164 1.247
      100.00 1.09744 1.315
      125.00 1.09351 1.384
      150.00 1.08984 1.453 /
28.19  70.00 1.12522 1.066
       95.00 1.12047 1.124
      120.00 1.11604 1.182
      145.00 1.11191 1.241
      170.00 1.10804 1.300 /
36.01  90.00 1.14458 0.964
      115.00 1.13959 1.014
      140.00 1.13494 1.064
      165.00 1.13060 1.115
      190.00 1.12653 1.166 /
44.09 110.00 1.16437 0.880
      135.00 1.15915 0.924
      160.00 1.15428 0.968
      185.00 1.14973 1.012
      210.00 1.14547 1.056 /
/
32.91  80.00 1.13304 1.04537
      114.00 1.12837 1.10009
      148.00 1.12401 1.15521
      182.00 1.11994 1.21063 /
40.99 100.00 1.15276 0.97219
      134.00 1.14786 1.02086
      168.00 1.14328 1.06983
      202.00 1.13900 1.11901 /
49.36 120.00 1.17297 0.91124
      154.00 1.16783 0.95496
      188.00 1.16303 0.99891
      222.00 1.15854 1.04301 /
58.04 140.00 1.19374 0.85942
      174.00 1.18836 0.89902
      208.00 1.18334 0.93878
      242.00 1.17864 0.97864 /
/
)"  };

    const auto es = parse(rspec, props);

    auto tables = ::Opm::Tables(es.getUnits());
    tables.addPVTTables(es);

    const auto& tabdims = tables.tabdims();
    const auto& tab     = tables.tab();

    const auto ibpvto = tabdims[ Ix::PvtoMainStart ] - 1;
    const auto jbpvto = tabdims[ Ix::PvtoCompStart ] - 1;
    const auto nppvto = tabdims[ Ix::NumPvtoPressNodes ];
    const auto nrpvto = tabdims[ Ix::NumPvtoCompNodes ];
    const auto ntpvto = tabdims[ Ix::NumPvtoTables ];
    const auto ncol   = 5;

    BOOST_CHECK_EQUAL(nppvto, 5);
    BOOST_CHECK_EQUAL(nrpvto, 4);
    BOOST_CHECK_EQUAL(ntpvto, 2);

    const auto pvto = std::vector<double> {
        &tab[ ibpvto ] + 0,
        &tab[ ibpvto ] + ntpvto*nrpvto*nppvto*ncol
    };

    const auto rs = std::vector<double> {
        &tab[ jbpvto ] + 0,
        &tab[ jbpvto ] + ntpvto*nrpvto
    };

    const auto expect_pvto = makeTable(5, {
        // Po                     1/Bo                      1/(Bo*mu_o)               d(1/Bo)/dPo               d(1/(Bo*mu_o))/dPo
        //
        // Table 1 (Comp 1)
        5.000000000000001e+01,    9.040365230755323e-01,    7.661326466741798e-01,    2.000000000000000e+20,    2.000000000000000e+20,
        7.500000000000000e+01,    9.077375549181221e-01,    7.279370929575959e-01,    1.480412737035941e-04,   -1.527822148663356e-03,
        1.000000000000000e+02,    9.112115468727220e-01,    6.929365375457962e-01,    1.389596781839940e-04,   -1.400022216471987e-03,
        1.250000000000000e+02,    9.144863787253888e-01,    6.607560539923329e-01,    1.309932741066744e-04,   -1.287219342138530e-03,
        1.500000000000000e+02,    9.175658812302724e-01,    6.314975094496025e-01,    1.231801001953415e-04,   -1.170341781709219e-03,

        // Table 1 (Comp 2) ----------------------------------------------------------------------------------------------------------

        7.000000000000000e+01,    8.887150957146157e-01,    8.336914593945738e-01,    2.000000000000000e+20,    2.000000000000000e+20,
        9.500000000000001e+01,    8.924826189009969e-01,    7.940236822962605e-01,    1.507009274552472e-04,   -1.586711083932530e-03,
        1.200000000000000e+02,    8.960252320705352e-01,    7.580585719716880e-01,    1.417045267815320e-04,   -1.438604412982900e-03,
        1.450000000000000e+02,    8.993533649306149e-01,    7.247005358022682e-01,    1.331253144031886e-04,   -1.334321446776793e-03,
        1.700000000000000e+02,    9.024944947835819e-01,    6.942265344489090e-01,    1.256451941186798e-04,   -1.218960054134368e-03,

        // Table 1 (Comp 3) ----------------------------------------------------------------------------------------------------------

        9.000000000000001e+01,    8.736829229935872e-01,    9.063100860929328e-01,    2.000000000000000e+20,    2.000000000000000e+20,
        1.150000000000000e+02,    8.775085776463464e-01,    8.653930746019195e-01,    1.530261861103677e-04,   -1.636680459640534e-03,
        1.400000000000000e+02,    8.811038468993955e-01,    8.281051192663491e-01,    1.438107701219638e-04,   -1.491518213422816e-03,
        1.650000000000000e+02,    8.844861135680170e-01,    7.932610884018088e-01,    1.352906667448606e-04,   -1.393761234581614e-03,
        1.900000000000000e+02,    8.876816418559648e-01,    7.613050101680658e-01,    1.278211315179111e-04,   -1.278243129349715e-03,

        // Table 1 (Comp 4) ----------------------------------------------------------------------------------------------------------

        1.100000000000000e+02,    8.588335322964350e-01,    9.759471957914034e-01,    2.000000000000000e+20,    2.000000000000000e+20,
        1.350000000000000e+02,    8.627011171979468e-01,    9.336592177466957e-01,    1.547033960604739e-04,   -1.691519121788311e-03,
        1.600000000000000e+02,    8.663409224798143e-01,    8.949802918179900e-01,    1.455922112746988e-04,   -1.547157037148228e-03,
        1.850000000000000e+02,    8.697694241256644e-01,    8.594559526933443e-01,    1.371400658340026e-04,   -1.420973564985826e-03,
        2.100000000000000e+02,    8.730040943892027e-01,    8.267084227170479e-01,    1.293868105415319e-04,   -1.309901199051855e-03,

        // ===========================================================================================================================

        // Table 2 (Comp 1)
        8.000000000000000e+01,    8.825813740026830e-01,    8.442765470624592e-01,    2.000000000000000e+20,    2.000000000000000e+20,
        1.140000000000000e+02,    8.862341253312299e-01,    8.056014738168967e-01,    1.074338626043212e-04,   -1.137502154281250e-03,
        1.480000000000000e+02,    8.896718000729531e-01,    7.701385895836714e-01,    1.011080806389172e-04,   -1.043026006859568e-03,
        1.820000000000000e+02,    8.929049770523422e-01,    7.375539818543586e-01,    9.509344057026681e-05,   -9.583708155680233e-04,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,

        // Table 2 (Comp 2) ----------------------------------------------------------------------------------------------------------

        1.000000000000000e+02,    8.674832575731288e-01,    8.922980668111468e-01,    2.000000000000000e+20,    2.000000000000000e+20,
        1.340000000000000e+02,    8.711863816144825e-01,    8.533847752037326e-01,    1.089154129809896e-04,   -1.144508576688653e-03,
        1.680000000000000e+02,    8.746763697431950e-01,    8.175844477563677e-01,    1.026467096680142e-04,   -1.052950807275436e-03,
        2.020000000000000e+02,    8.779631255487269e-01,    7.845891685943172e-01,    9.666928839799841e-05,   -9.704493871191340e-04,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,

        // Table 2 (Comp 3) ----------------------------------------------------------------------------------------------------------

        1.200000000000000e+02,    8.525367230193440e-01,    9.355786873044905e-01,    2.000000000000000e+20,    2.000000000000000e+20,
        1.540000000000000e+02,    8.562890146682309e-01,    8.966752687738030e-01,    1.103615190849091e-04,   -1.144218192079043e-03,
        1.880000000000000e+02,    8.598230484166358e-01,    8.607612782098846e-01,    1.039421690707318e-04,   -1.056293840115247e-03,
        2.220000000000000e+02,    8.631553507000190e-01,    8.275619128292337e-01,    9.800889068774162e-05,   -9.764519229603183e-04,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,

        // Table 2 (Comp 4) ----------------------------------------------------------------------------------------------------------

        1.400000000000000e+02,    8.377033524888167e-01,    9.747310424342193e-01,    2.000000000000000e+20,    2.000000000000000e+20,
        1.740000000000000e+02,    8.414958430105355e-01,    9.360145970173471e-01,    1.115438388740827e-04,   -1.138718982849180e-03,
        2.080000000000000e+02,    8.450656616019064e-01,    9.001743343508666e-01,    1.049946644520869e-04,   -1.054125372543546e-03,
        2.420000000000000e+02,    8.484354849657233e-01,    8.669536141642721e-01,    9.911245187696645e-05,   -9.770800054880735e-04,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        });

    const auto expect_rs = makeTable(1, {
        // Table 1
        20.59, 28.19, 36.01, 44.09,

        // Table 2
        32.91, 40.99, 49.36, 58.04,
    });

    check_is_close(pvto, expect_pvto);
    check_is_close(rs  , expect_rs  );
}

BOOST_AUTO_TEST_CASE (PVTO_Exceed_Tabdims_Limits)
{
    // This checks that Flow's extended table allocation scheme does what
    // it's supposed to do.  Normally, one would announce the maximum sizes
    // in the RUNSPEC keyword 'TABDIMS'.  Note that the maximum sizes need
    // to be big enough in order to run the case in ECLIPSE.  Other than
    // NTPVT, Flow does not really care about these declared maximum sizes.

    const auto rspec = std::string { R"(RUNSPEC
DIMENS
  10 10 10 /

TITLE
  Test PVTO Output

OIL
WATER

METRIC

TABDIMS
-- NTSFUN  NTPVT  NSSFUN  NPPVT  NTFIP  NRPVT
   1*      2      1*      2      1*     1
/
)"  };

    const auto props = std::string { R"(
PVTO
20.59  50.00 1.10615 1.180
       75.00 1.10164 1.247 /
28.19  70.00 1.12522 1.066 /
44.09 110.00 1.16437 0.880
      135.00 1.15915 0.924
      160.00 1.15428 0.968
      185.00 1.14973 1.012
      210.00 1.14547 1.056 /
/
32.91  80.00 1.13304 1.04537
      114.00 1.12837 1.10009 /
40.99 100.00 1.15276 0.97219
      134.00 1.14786 1.02086
      168.00 1.14328 1.06983 /
49.36 120.00 1.17297 0.91124
      154.00 1.16783 0.95496 /
58.04 140.00 1.19374 0.85942
      174.00 1.18836 0.89902 /
/
)"  };

    const auto es = parse(rspec, props);

    auto tables = ::Opm::Tables(es.getUnits());
    tables.addPVTTables(es);

    const auto& tabdims = tables.tabdims();
    const auto& tab     = tables.tab();

    const auto ibpvto = tabdims[ Ix::PvtoMainStart ] - 1;
    const auto jbpvto = tabdims[ Ix::PvtoCompStart ] - 1;
    const auto nppvto = tabdims[ Ix::NumPvtoPressNodes ];
    const auto nrpvto = tabdims[ Ix::NumPvtoCompNodes ];
    const auto ntpvto = tabdims[ Ix::NumPvtoTables ];
    const auto ncol   = 5;

    // Verify declared TABDIMS from input
    {
        const auto& tabd = es.runspec().tabdims();

        BOOST_CHECK_EQUAL(tabd.getNumPVTTables(),     2U);
        BOOST_CHECK_EQUAL(tabd.getNumRSNodes(),       1U);
        BOOST_CHECK_EQUAL(tabd.getNumPressureNodes(), 2U);
    }

    // Verify active TABDIMS from dynamic sizes
    BOOST_CHECK_EQUAL(nppvto, 5); // Table 1, Comp 3
    BOOST_CHECK_EQUAL(nrpvto, 4); // Table 2
    BOOST_CHECK_EQUAL(ntpvto, 2);

    const auto pvto = std::vector<double> {
        &tab[ ibpvto ] + 0,
        &tab[ ibpvto ] + ntpvto*nrpvto*nppvto*ncol
    };

    const auto rs = std::vector<double> {
        &tab[ jbpvto ] + 0,
        &tab[ jbpvto ] + ntpvto*nrpvto
    };

    const auto expect_pvto = makeTable(5, {
        // Po                     1/Bo                      1/(Bo*mu_o)               d(1/Bo)/dPo               d(1/(Bo*mu_o))/dPo
        //
        // Table 1 (Comp 1)
        5.000000000000001e+01,    9.040365230755323e-01,    7.661326466741798e-01,    2.000000000000000e+20,    2.000000000000000e+20,
        7.500000000000000e+01,    9.077375549181221e-01,    7.279370929575959e-01,    1.480412737035941e-04,   -1.527822148663356e-03,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,

        // Table 1 (Comp 2) ----------------------------------------------------------------------------------------------------------

        7.000000000000000e+01,    8.887150957146157e-01,    8.336914593945738e-01,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,

        // Table 1 (Comp 3) ----------------------------------------------------------------------------------------------------------

        1.100000000000000e+02,    8.588335322964350e-01,    9.759471957914034e-01,    2.000000000000000e+20,    2.000000000000000e+20,
        1.350000000000000e+02,    8.627011171979468e-01,    9.336592177466957e-01,    1.547033960604739e-04,   -1.691519121788311e-03,
        1.600000000000000e+02,    8.663409224798143e-01,    8.949802918179900e-01,    1.455922112746988e-04,   -1.547157037148228e-03,
        1.850000000000000e+02,    8.697694241256644e-01,    8.594559526933443e-01,    1.371400658340026e-04,   -1.420973564985826e-03,
        2.100000000000000e+02,    8.730040943892027e-01,    8.267084227170479e-01,    1.293868105415319e-04,   -1.309901199051855e-03,

        // Table 1 (Comp 4 -- unused) ------------------------------------------------------------------------------------------------

        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,

        // ===========================================================================================================================

        // Table 2 (Comp 1)
        8.000000000000000e+01,    8.825813740026830e-01,    8.442765470624592e-01,    2.000000000000000e+20,    2.000000000000000e+20,
        1.140000000000000e+02,    8.862341253312299e-01,    8.056014738168967e-01,    1.074338626043212e-04,   -1.137502154281250e-03,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,

        // Table 2 (Comp 2) ----------------------------------------------------------------------------------------------------------

        1.000000000000000e+02,    8.674832575731288e-01,    8.922980668111468e-01,    2.000000000000000e+20,    2.000000000000000e+20,
        1.340000000000000e+02,    8.711863816144825e-01,    8.533847752037326e-01,    1.089154129809896e-04,   -1.144508576688653e-03,
        1.680000000000000e+02,    8.746763697431950e-01,    8.175844477563677e-01,    1.026467096680142e-04,   -1.052950807275436e-03,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,

        // Table 2 (Comp 3) ----------------------------------------------------------------------------------------------------------

        1.200000000000000e+02,    8.525367230193440e-01,    9.355786873044905e-01,    2.000000000000000e+20,    2.000000000000000e+20,
        1.540000000000000e+02,    8.562890146682309e-01,    8.966752687738030e-01,    1.103615190849091e-04,   -1.144218192079043e-03,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,

        // Table 2 (Comp 4) ----------------------------------------------------------------------------------------------------------

        1.400000000000000e+02,    8.377033524888167e-01,    9.747310424342193e-01,    2.000000000000000e+20,    2.000000000000000e+20,
        1.740000000000000e+02,    8.414958430105355e-01,    9.360145970173471e-01,    1.115438388740827e-04,   -1.138718982849180e-03,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
        2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,    2.000000000000000e+20,
    });

    const auto expect_rs = makeTable(1, {
        // Table 1
        20.59, 28.19, 44.09, +2.0e20,

        // Table 2
        32.91, 40.99, 49.36, 58.04,
    });

    check_is_close(pvto, expect_pvto);
    check_is_close(rs  , expect_rs  );
}

BOOST_AUTO_TEST_SUITE_END ()

// =====================================================================

BOOST_AUTO_TEST_SUITE (Water)

BOOST_AUTO_TEST_CASE (PVTW)
{
    const auto rspec = std::string { R"(RUNSPEC
DIMENS
  10 10 10 /

TITLE
  Test PVTW Output

WATER

METRIC

TABDIMS
-- NTSFUN  NTPVT  NSSFUN  NPPVT  NTFIP  NRPVT
   1*      2      1*      4      1*     3
/
)"  };

    const auto props = std::string { R"(
PVTW
-- Pref  Bw(Pref)  Cw        Vw(Pref)  Cv
   200   1.23      0.321e-4  0.25      0.654e-3 /
   250   0.987     1.234e-5  0.314     0.9876e-5 /
)"  };

    const auto es = parse(rspec, props);

    auto tables = ::Opm::Tables(es.getUnits());
    tables.addPVTTables(es);

    const auto& tabdims = tables.tabdims();
    const auto& tab     = tables.tab();

    const auto ibpvtw = tabdims[ Ix::PvtwStart ] - 1;
    const auto ntpvtw = tabdims[ Ix::NumPvtwTables ];
    const auto ncol   = 5;

    BOOST_CHECK_EQUAL(ntpvtw, 2);

    const auto pvtw = std::vector<double> {
        &tab[ ibpvtw ] + 0,
        &tab[ ibpvtw ] + ntpvtw*ncol
    };

    const auto expect_pvtw = makeTable(5, {
        // Pw                     1/Bw                      Cw                        1/(Bw*mu_w)               Cw - Cv
        2.000000000000000e+02,    8.130081300813008e-01,    3.210000000000000e-05,    3.252032520325203e+00,   -6.219000000000000e-04,
        2.500000000000000e+02,    1.013171225937183e+00,    1.234000000000000e-05,    3.226659955213960e+00,    2.464000000000000e-06,
    });

    check_is_close(pvtw, expect_pvtw);
}

BOOST_AUTO_TEST_SUITE_END ()

// =====================================================================

BOOST_AUTO_TEST_SUITE_END ()

// =====================================================================

BOOST_AUTO_TEST_SUITE (Density)

BOOST_AUTO_TEST_CASE (Single_Region)
{
    const auto input = std::string { R"(RUNSPEC
DIMENS
  10 10 10 /

TITLE
  Test DENSITY Output

OIL
WATER

METRIC

TABDIMS
-- NTSFUN  NTPVT  NSSFUN  NPPVT  NTFIP  NRPVT
   1*      1      1*      4      1*     3
/

GRID
INIT
DXV
  10*100 /
DYV
  10*100 /
DZV
  10*10 /

DEPTHZ
  121*2000 /

PERMX
  1000*100.0 /

COPY
  'PERMX' 'PERMY' /
  'PERMX' 'PERMZ' /
/

MULTIPLY
  'PERMZ' 0.1 /
/

PORO
  1000*0.3 /

PROPS
DENSITY
  859.1 1033.2 0.859 /

END
)"  };

    const auto es = ::Opm::EclipseState { Opm::Parser{}.parseString(input) };

    auto tables = ::Opm::Tables(es.getUnits());
    tables.addDensity(es.getTableManager().getDensityTable());

    const auto& tabdims = tables.tabdims();
    const auto& tab     = tables.tab();

    const auto ibdens = tabdims[ Ix::DensityTableStart ] - 1;
    const auto ntdens = tabdims[ Ix::DensityNumTables ];
    const auto ncol   = 3;

    BOOST_CHECK_EQUAL(ntdens, 1);

    const auto density = std::vector<double> {
        &tab[ ibdens ] + 0,
        &tab[ ibdens ] + ntdens*ncol
    };

    const auto expect_density = makeTable(ncol, {
        // rhoOS    rhoWS      rhoGS
        859.1,      1033.2,    0.859,
    });

    check_is_close(density, expect_density);
}

BOOST_AUTO_TEST_CASE (Multi_Region)
{
    const auto input = std::string { R"(RUNSPEC
DIMENS
  10 10 10 /

TITLE
  Test DENSITY Output

OIL
WATER

METRIC

TABDIMS
-- NTSFUN  NTPVT  NSSFUN  NPPVT  NTFIP  NRPVT
   1*      4      1*      4      1*     3
/

GRID
INIT
DXV
  10*100 /
DYV
  10*100 /
DZV
  10*10 /

DEPTHZ
  121*2000 /

PERMX
  1000*100.0 /

COPY
  'PERMX' 'PERMY' /
  'PERMX' 'PERMZ' /
/

MULTIPLY
  'PERMZ' 0.1 /
/

PORO
  1000*0.3 /

PROPS
DENSITY
  859.1 1035.4 0.8591 /
  860.2 1037.6 0.8592 /
  861.3 1039.8 0.8593 /
  862.4 1042.0 0.8594 /

END
)"  };

    const auto es = ::Opm::EclipseState { Opm::Parser{}.parseString(input) };

    auto tables = ::Opm::Tables(es.getUnits());
    tables.addDensity(es.getTableManager().getDensityTable());

    const auto& tabdims = tables.tabdims();
    const auto& tab     = tables.tab();

    const auto ibdens = tabdims[ Ix::DensityTableStart ] - 1;
    const auto ntdens = tabdims[ Ix::DensityNumTables ];
    const auto ncol   = 3;

    BOOST_CHECK_EQUAL(ntdens, 4);

    const auto density = std::vector<double> {
        &tab[ ibdens ] + 0,
        &tab[ ibdens ] + ntdens*ncol
    };

    const auto expect_density = makeTable(ncol, {
        // rhoOS    rhoWS      rhoGS
        859.1,      1035.4,    0.8591,
        860.2,      1037.6,    0.8592,
        861.3,      1039.8,    0.8593,
        862.4,      1042.0,    0.8594,
    });

    check_is_close(density, expect_density);
}

BOOST_AUTO_TEST_SUITE_END ()    // Density
